【问题标题】:display a record which contains a VARRAY column显示包含 VARRAY 列的记录
【发布时间】:2016-10-31 09:55:31
【问题描述】:

我有一个返回记录的函数。 记录的列之一是 VARRAY。 有人可以提示我如何显示记录吗? (我的问题与 VARRAY 列有关。

create or replace TYPE phone_list_typ AS VARRAY(5) OF VARCHAR2(25);

CREATE TABLE "CUSTOMERS" 
    ("CUSTOMER_ID" NUMBER(6,0), 
     "CUST_FIRST_NAME" VARCHAR2(20 BYTE)
     "PHONE_NUMBERS" "OE"."PHONE_LIST_TYP" , 
     "CREDIT_LIMIT" NUMBER(9,2), 
     "CUST_EMAIL" VARCHAR2(40 BYTE)); 

TYPE r_cust_det IS RECORD( CUSTOMER_ID      customers.CUSTOMER_ID%TYPE
                         , CUST_FIRST_NAME  customers.CUST_FIRST_NAME%TYPE
                         , PHONE_NUMBERS    customers.PHONE_NUMBERS%TYPE
                         , CREDIT_LIMIT     customers.CREDIT_LIMIT%TYPE
                         , CUST_EMAIL       customers.CUST_EMAIL%TYPE);

CREATE OR REPLACE FUNCTION show_customer_details (n_customer_id customers.customer_id%TYPE) RETURN r_cust_det
IS
    v_return r_cust_det;
BEGIN
    SELECT CUSTOMER_ID
         , CUST_FIRST_NAME
         , PHONE_NUMBERS
         , CREDIT_LIMIT
         , CUST_EMAIL
    INTO v_return
    FROM CUSTOMERS
    WHERE CUSTOMER_ID = n_customer_id;
RETURN v_return;
END show_customer_details;

【问题讨论】:

    标签: plsql record varray


    【解决方案1】:

    这可能取决于您希望它的外观和显示介质是什么(文本文件、交互式网页等),但一种方法可能是将电话号码列为逗号分隔的列表。

    select customer_id, cust_first_name, credit_limit, cust_email
         , listagg(p.column_value,', ') within group (order by p.column_value) as phone_numbers
    from   customers c cross join table(c.phone_numbers) p
    group by customer_id, cust_first_name, credit_limit, cust_email
    order by customer_id;
    

    不过,我不确定您对 show_customer_details 函数的期望。

    (顺便说一句,将标识符括在双引号中并不是一个好主意,除非您绝对必须这样做。)

    【讨论】:

    • 我希望结果显示为“每行一个信息”。在枚举的情况下,您的解决方案完全匹配。对于表格解决方案,我发现了这个:
    • 另一种方法可能是控制中断报告。如何构建取决于显示媒体。
    • 该函数用于训练目的
    【解决方案2】:
    CREATE OR REPLACE FUNCTION show_customer_details (n_customer_id customers.customer_id%TYPE) RETURN t_cust_det PIPELINED
        IS
            v_return t_cust_det;
        BEGIN
            SELECT t1.CUSTOMER_ID
                 , t1.CUST_FIRST_NAME
                 , t2.*
                 , t1.CREDIT_LIMIT
                 , t1.CUST_EMAIL
            BULK COLLECT INTO v_return
            FROM CUSTOMERS t1, table(t1.phone_numbers) t2
            WHERE t1.CUSTOMER_ID = n_customer_id
            AND column_value is not null;
    
            FOR i IN 1 .. v_return.count
            LOOP
                PIPE ROW (v_return(i));
            END LOOP;
    
        END show_customer_details;
    

    函数调用是:

    select * from table(SHOW_DETAILS.SHOW_CUSTOMER_DETAILS(101));
    

    【讨论】:

    • 应该可以。但是,如果您一次获取所有行(并且可能每个客户 ID 没有那么多行),我认为它不需要是流水线函数。我只是让它返回数组。
    • 使用了PIPELINED,因为SQL中没有定义记录类型的表。
    • 确定t_cust_det 是表格类型吗?只需让函数返回 v_return 而不使用管道。
    • 是的,它是记录表。不同之处在于收集数据的方式。在您的情况下,所有电话号码都被选中,“连接”在一行中,用逗号分隔。就我而言,每个电话号码都是在单独的行中选择的。如果有 3 个电话号码,则 select 语句将返回 3 行(每个电话号码单独一行);其余的值被重复。
    【解决方案3】:

    我发现的另一种不使用 PIPELINED 的解决方案是:

    定义一个对象类型

    create or replace type customers_typ
    is object 
        ( CUSTOMER_ID      number(6)
        , CUST_FIRST_NAME  varchar2(20)
        , PHONE_NUMBERS    varchar2(25) --phone_list_typ
        , CREDIT_LIMIT     number(9, 2)
        , CUST_EMAIL       varchar2(40)
        );
    

    定义一个新类型,先前定义的对象的表。

    create or replace type t_customers_typ is table of customers_typ;
    

    函数变成

    CREATE OR REPLACE FUNCTION show_customer_details (n_customer_id customers.customer_id%TYPE) RETURN t_customers_typ
    IS
        v_return t_customers_typ;
    BEGIN
        SELECT customers_typ(t1.CUSTOMER_ID
             , t1.CUST_FIRST_NAME
             , t2.column_value
             , t1.CREDIT_LIMIT
             , t1.CUST_EMAIL)
        BULK COLLECT INTO v_return
        FROM CUSTOMERS t1, table(t1.phone_numbers) t2
        WHERE t1.CUSTOMER_ID = n_customer_id
        AND t2.column_value is not null;
    
        return v_return;
    
    END show_customer_details;
    

    函数调用方式相同:

    select * from table(SHOW_DETAILS.SHOW_CUSTOMER_DETAILS(101));
    

    【讨论】:

      猜你喜欢
      • 2016-08-03
      • 2015-08-04
      • 2023-03-15
      • 2010-09-06
      • 1970-01-01
      • 2019-06-10
      • 1970-01-01
      • 2021-03-09
      相关资源
      最近更新 更多