编写一个 function/procedure 将大约 150k 行合并为一个并将其作为输出发送以便能够从 UI 下载

Write a function/procedure to combine around 150k rows into one and send it as output to be able to download from UI

我想就执行下面提到的场景的最佳方法获得一些意见。我只是在这里寻找替代的最佳方法,而不是调试错误。

我有一个 select 语句,它产生大约 150K 行和大约 10 列。我需要用制表符分隔符连接列,然后遍历每一行并将它们组合成一行。此列值正在使用函数调用并从 UI.

下载

当前方法: 编写一个流水线函数以将其作为 clob 输出并使用它从 UI.

下载
TYPE OUT_REC_CSV_TYP IS  RECORD
    ( object_status                    VARCHAR2        ( 4000    ) ,
     extract_csv                    CLOB    ) ;

TYPE OUT_REC_CSV_TABTYP IS TABLE OF OUT_REC_CSV_TYP;

FUNCTION GET_CSV_EXTRACT (P_DATE_REPORTED   IN VARCHAR2,
                          P__USER_ID        IN NUMBER DEFAULT NULL)
    RETURN OUT_REC_CSV_TABTYP
    PIPELINED
IS
    V_OUT_REC         OUT_REC_CSV_TYP;
    V_OUT_REC_EMPTY   OUT_REC_CSV_TYP;
BEGIN
    V_OUT_REC := V_OUT_REC_EMPTY;
    V_OUT_REC.OBJECT_STATUS := NULL;                         --- ADDING HEADER

    SELECT 'COLUMN_A' || CHR (9) || 'COLUMN_B'     AS extract_csv --have around 15 columns
      INTO V_OUT_REC.extract_csv
      FROM DUAL;

    FOR i IN (SELECT 'COLUMN_A' || CHR (9) || 'COLUMN_B'     AS extract_csv
                FROM (WITH
                          TABLE_A AS (SELECT * FROM table_1),
                          TABLE_B AS (SELECT * FROM table_2)
                      SELECT COLUMN_A, COLUMN_B
                        FROM TABLE_A, TABLE_B
                       WHERE TABLE_A.COLUMN_NAME = TABLE_B.COLUMN_NAME))
    LOOP
        V_OUT_REC.extract_csv :=
            V_OUT_REC.extract_csv || CHR (10) || i.extract_csv;
    END LOOP;

    PIPE ROW (V_OUT_REC);
    RETURN;
END GET_CSV_EXTRACT;

select extract_csv from TABLE(PACKAGE_NAME.GET_CSV_EXTRACT('04/19/2021','1'));

我可能措辞有误。 预期输出:所有行合并为一个,由新行分隔 COL_A COL_B COL_C COL_D COL_E 155189 测试测试测试ABCD 127557 测试测试测试ABCD ....... 说大约 150K 行合并

这种方法有时会抛出错误,并在尝试下载此 clob 值文本文件几次后起作用。

(150K 行) * (10 列) 在一行中?那是你在说什么?谁能理解其中写的内容(注意 TAB 作为列分隔符,以及可能的 NULL 值)。

另一方面,您发布的代码看起来每一行都各占一行;这个:

V_OUT_REC.extract_csv := V_OUT_REC.extract_csv || CHR (10) || i.extract_csv;

我可能是错的,但我会说你的 words 与你的 code.


因此,换一种方法怎么样? SQL*Plus 及其 spool 命令。像这样:

SQL> set linesize 100
SQL> set pagesize 0
SQL> set colsep "       "    --> this is (double quotes) (pressed TAB on keyboard) (double quotes)
SQL> spool test.txt
SQL> select * from dept;
        10      ACCOUNTING      NEW YORK
        20      RESEARCH        DALLAS
        30      SALES           CHICAGO
        40      OPERATIONS      BOSTON

SQL> spool off;

就这么简单。


或者,如果它必须是存储过程,我宁愿考虑创建文件的 UTL_FILE。但是,这种方法需要访问一个目录(通常驻留在数据库服务器上)。

SQL> declare
  2    l_handle  utl_file.file_type;
  3    l_delim   varchar2(20) := chr(9);   -- TAB character
  4  begin
  5    l_handle := utl_file.fopen('EXT_DIR',
  6                               'test.txt',
  7                               'w');
  8
  9    for cur_r in (select deptno, dname, loc
 10                  from dept)
 11    loop
 12      utl_file.put_line(l_handle, cur_r.deptno || l_delim ||
 13                                  cur_r.dname  || l_delim ||
 14                                  cur_r.loc);
 15    end loop;
 16
 17    utl_file.fclose(l_handle);
 18  exception
 19    when others then
 20      utl_file.fclose(l_handle);
 21      raise;
 22  end;
 23  /

PL/SQL procedure successfully completed.

SQL> $type c:\temp\test.txt            --> because c:\temp is where EXT_DIR directory points to
10      ACCOUNTING      NEW YORK
20      RESEARCH        DALLAS
30      SALES   CHICAGO
40      OPERATIONS      BOSTON

SQL>