2

我有以下问题。我是一位经验丰富的 Java 程序员,但在 SQL 和 PL/SQL 方面有点不熟练。

我需要执行以下操作。

1 将一些数组和一些其他变量传入一个过程

2 循环数组中的值(它们都具有相同的项目数)并动态创建 SQL 语句

3 运行此语句并将其添加到结果集中(这是过程的 OUT 参数)

我已经有动态创建 SQL 查询、运行它并将结果添加到结果集(这是一个 REF CURSOR)的经验,但我不确定如何循环并将每次调用的结果添加到查询相同的结果集。我什至不确定这是否可能。

这是我到目前为止所拥有的(为简单起见编辑了代码)。我知道这是错误的,因为我只是用最新的查询结果替换了 RESULT_SET 的内容(这在调用此过程的 Java 中得到了确认)。

任何和所有的帮助将不胜感激。

TYPE REF_CURSOR IS REF CURSOR;  




PROCEDURE GET_DATA_FASTER(in_seq_numbers IN seq_numbers_array, in_values IN text_array, in_items IN text_array, list IN VARCHAR2, RESULT_SET OUT REF_CURSOR) AS  
  query_str VARCHAR2(4000);

  seq_number NUMBER;
  the_value VARCHAR2(10);
  the_item VARCHAR2(10);

  BEGIN

    FOR i IN 1..in_seq_numbers.COUNT
    LOOP

      seq_number := in_seq_numbers(i);
      the_value := trim(in_values(i));
      the_item := trim(in_items(i));

      query_str := 'SELECT distinct '||seq_number||' as seq, value, item
      FROM my_table ai';                    

      query_str := query_str || '
      WHERE ai.value = '''||the_value||''' AND ai.item = '''||the_item||'''
      AND ai.param = ''BOOK''
      AND ai.prod in (' || list || ');

      OPEN RESULT_SET FOR query_str;

    END LOOP;

    EXCEPTION WHEN OTHERS THEN
      RAISE;

  END GET_DATA_FASTER;
4

1 回答 1

4

流水线表函数似乎更适合您的需求,尤其是当您所做的只是检索数据时。请参阅http://www.oracle-base.com/articles/misc/pipelined-table-functions.php

您所做的是为输出行创建一个类型。因此,在您的情况下,您将创建一个对象,例如

CREATE TYPE get_data_faster_row AS OBJECT(
    seq    NUMBER(15,2),
    value  VARCHAR2(10),
    item   VARCHAR2(10)
);

然后创建一个表类型,它是由上面的行类型组成的表

CREATE TYPE get_data_faster_data IS TABLE OF get_data_faster_row;

然后创建以流水线方式返回数据的表函数。Oracle 中的流水线有点像 .net 中的收益回报(不确定您是否熟悉)。您找到所有您想要的行,并在循环中一次将它们“管道”出来。当您的函数完成时,返回的表包含您通过管道输出的所有行。

CREATE FUNCTION Get_Data_Faster(params) RETURN get_data_faster_data PIPELINED AS
BEGIN
    -- Iterate through your parameters 
        --Iterate through the results of the select using
        -- the current parameters. You'll probably need a 
        -- cursor for this
        PIPE ROW(get_data_faster_row(seq, value, item));
        LOOP;
    LOOP;
END;

编辑:在下面亚历克斯的评论之后,你需要这样的东西。我无法对此进行测试,但它应该可以帮助您入门:

CREATE FUNCTION Get_Data_Faster(in_seq_numbers IN seq_numbers_array, in_values IN text_array, in_items IN text_array, list IN VARCHAR2) RETURN get_data_faster_data PIPELINED AS
    TYPE r_cursor IS REF CURSOR;
    query_results r_cursor;
    results_out get_data_faster_row := get_data_faster_row(NULL, NULL, NULL);

    query_str VARCHAR2(4000);

    seq_number NUMBER;
    the_value VARCHAR2(10);
    the_item VARCHAR2(10);

BEGIN
    FOR i IN 1..in_seq_number.COUNT
    LOOP
        seq_number := in_seq_numbers(i);
        the_value := trim(in_values(i));
        the_item := trim(in_items(i));

        query_str := 'SELECT distinct '||seq_number||' as seq, value, item
        FROM my_table ai';                    

        query_str := query_str || '
        WHERE ai.value = '''||the_value||''' AND ai.item = '''||the_item||'''
        AND ai.param = ''BOOK''
        AND ai.prod in (' || list || ');

        OPEN query_results FOR query_str;

        LOOP
            FETCH query_results INTO 
                results_out.seq,
                results_out.value,
                results_out.item;
            EXIT WHEN query_results%NOTFOUND;
            PIPE ROW(results_out);
        END LOOP;

    CLOSE query_results;

    END LOOP;

END;

下面亚历克斯评论中的额外信息对答案很有用:

您可以有来自不同来源的多个循环,并且只要将每个循环中的数据放入相同的对象类型中,您就可以在函数中的任何位置使用管道行语句将它们抽出。调用者将它们视为一个表,其中的行按照您管道的顺序排列。与其调用过程并获取结果集作为输出参数,不如查询为 select seq, value, item from table(package.get_data_faster(a, b, c, d)),当然你仍然可以有一个如果它们的管道顺序不是您想要的,则 order by 子句。

于 2012-09-26T15:25:11.120 回答