在oracle中的匿名块中引用通用游标

时间:2014-12-29 17:40:22

标签: sql oracle

在包pkg_cost_api中,定义了以下内容。

TYPE t_ref_generic              IS REF CURSOR;

以下是同一包中的程序。

PROCEDURE transfer_costs

(

        p_source_isbn             IN product_header.mhid_part_nbr%TYPE,
        p_dest_isbn               IN product_header.mhid_part_nbr%TYPE,
        p_plant_mfg_flag          IN VARCHAR2,
        p_employee_number         IN product_header.add_by%TYPE,
        p_transfer_results        OUT pkg_cost_api.t_ref_generic
) IS

        v_gen_cost_rec                  t_gen_cost_record := t_gen_cost_record(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);

        v_result_set                    t_gen_cost_table := t_gen_cost_table();
BEGIN
        -- relevant code
        Loop

                v_gen_cost_rec.initialize();
                v_gen_cost_rec.gen_cost_code := 'some value';
                v_gen_cost_rec.gen_cost_code_desc := 'some value';
                v_gen_cost_rec.amount := 'some value';
                v_result_set.EXTEND;
                v_result_set(v_result_set.COUNT) := v_gen_cost_rec;

        End Loop;

       OPEN p_transfer_results FOR

       SELECT *
               FROM TABLE(CAST(v_result_set AS t_gen_cost_table)) gen_costs;

END;

类型t_gen_cost_record是:

CREATE OR REPLACE TYPE t_gen_cost_record AS
OBJECT

(

    gen_cost_code      VARCHAR2(30),
    gen_cost_code_desc VARCHAR2(100),
    amount             NUMBER,
    cost_code          VARCHAR2(30),
    acct_category_code VARCHAR2(30),
    category_desc      VARCHAR2(100),
    category_code      VARCHAR2(30),
    oracle_task_code   VARCHAR2(3),
    MEMBER PROCEDURE initialize
);

我试图在脚本下面运行。

DECLARE

    c_transfer_results          pkg_cost_api.t_ref_generic;

    v_finance_source_note       product_note.note%TYPE;
    v_comments                  nopc.comments%TYPE;
    v_dest_comments             nopc.comments%TYPE;

    v_nopc_isbn                 nopc.isbn%TYPE := '0077449835';
    v_move_plant_flag           nopc.move_plant_flag%TYPE;
    v_move_to_isbn              nopc.move_to_isbn%TYPE := '0077364678';

    v_gen_cost_code         VARCHAR2(30);
    v_gen_cost_code_desc    VARCHAR2(100);
    v_amount                NUMBER;


BEGIN

 pkg_cost_api.transfer_costs(

                    p_source_isbn => v_nopc_isbn,
                    p_dest_isbn => v_move_to_isbn,
                    p_plant_mfg_flag => 'PLANT',
                    p_employee_number => '000159457',
                    p_transfer_results => c_transfer_results
                );
            v_dest_comments := Chr(10) || ' Note Date: ' || SYSDATE;
            v_finance_source_note := Chr(10) || ' Note Date: ' || SYSDATE;

            LOOP
            FETCH c_transfer_results INTO v_gen_cost_code, v_gen_cost_code_desc, v_amount;

                EXIT WHEN c_transfer_results%NOTFOUND;

                v_comments := v_comments || CHR(10) || 'Plant Transfer from ' ||  v_nopc_isbn || ' to ' || v_move_to_isbn ||
                            ' Amounts: ' || v_gen_cost_code_desc || ': ' || v_amount || CHR(10);

                v_finance_source_note := v_finance_source_note || CHR(10) || 'Plant Transfer from ' || v_nopc_isbn || ' to ' || v_move_to_isbn ||
                            ' Amounts: ' || v_gen_cost_code_desc || ': ' || v_amount || CHR(10);

                v_dest_comments := v_dest_comments || CHR(10) ||
                            'Plant Transfer to ' || v_move_to_isbn || ' from ' || v_nopc_isbn ||
                            ' Amounts: ' || v_gen_cost_code_desc || ': ' || v_amount || CHR(10);

            END LOOP;

EXCEPTION

  WHEN OTHERS THEN

   RAISE;

END;

当我尝试运行上面的独立脚本时,我收到以下错误:

Error report:
ORA-06504: PL/SQL: Return types of Result Set variables or query do not match
ORA-06512: at line 39 06504. 00000 - "PL/SQL: Return types of Result Set variables or query do not match"
*Cause: Number and/or types of columns in a query does not match declared return type of a result set variable, or declared types of two Result Set variables do not match.
*Action: Change the program statement or declaration. Verify what query the variable actually refers to during execution.

请有人告诉我这里到底出错了什么。

2 个答案:

答案 0 :(得分:0)

当查询中有八个来自对象类型时,您尝试将引用光标提取到三列中。我不认为有任何方法直接获取对象,但您可以定义一个与对象结构相同的本地记录类型:

DECLARE
    TYPE l_gen_cost_record IS RECORD
    (
      gen_cost_code      VARCHAR2(30),
      gen_cost_code_desc VARCHAR2(100),
      amount             NUMBER,
      cost_code          VARCHAR2(30),
      acct_category_code VARCHAR2(30),
      category_desc      VARCHAR2(100),
      category_code      VARCHAR2(30),
      oracle_task_code   VARCHAR2(3)
    );

    v_gen_cost_rec              l_gen_cost_record;

    c_transfer_results          pkg_cost_api.t_ref_generic;

...

然后进入:

            LOOP
            FETCH c_transfer_results INTO v_gen_cost_rec;

并参考该记录的字段而不是冗余的v_amount等变量:

                v_comments := v_comments || CHR(10)
                        || 'Plant Transfer from ' ||  v_nopc_isbn
                        || ' to ' || v_move_to_isbn
                        || ' Amounts: ' || v_gen_cost_rec.gen_cost_code_desc
                        || ': ' || v_gen_cost_rec.amount || CHR(10);

This SQL Fiddle demo编译并运行,使用固定数据类型而不是%TYPE变量。

将集合作为OUT变量并直接使用它可能更简单,但它取决于使用它的其他位置。如果你需要两者,你可以有一个填充集合的过程,以及一个调用它的包装器过程并打开一个引用光标以给你灵活性。 (或者一个流水线函数,或任何适合你如何使用结果的函数)。

顺便说一句,不要抓住when others例外;你重新提升它,这是一种东西,但是你失去了异常的实际位置,如果它破坏了它将使调试变得更加困难。只捕获您需要处理的特定异常。

答案 1 :(得分:0)

定义具有相同属性的本地类型t_ref_gen_record将起作用,但需要将匿名块添加为另一个包中的过程。所以我所做的是在脚本中初始化相同的变量,如在类型中,并使用fetch将transfer_costs的out参数的值输入到这些变量中。这工作得很好。我只使用三个变量的原因是因为在transfer_costs过程中,类型被初始化,并且其中只有三个变量被赋予了值。我现在纠正了它。