我有一个将数据加载到文件中的流水线功能。
以下是功能代码。
CREATE OR REPLACE FUNCTION DATA_UNLOAD
( p_source IN SYS_REFCURSOR,
p_filename IN VARCHAR2,
p_directory IN VARCHAR2
) RETURN dump_ntt PIPELINED PARALLEL_ENABLE (PARTITION p_source BY ANY)
AS
TYPE row_ntt IS TABLE OF VARCHAR2(32767);
v_rows row_ntt;
v_file UTL_FILE.FILE_TYPE;
v_buffer VARCHAR2(32767);
v_sid VARCHAR(255);
v_name VARCHAR2(255);
v_lines PLS_INTEGER := 0;
v_start_dttm TIMESTAMP WITH TIME ZONE:= SYSTIMESTAMP;
v_end_dttm TIMESTAMP WITH TIME ZONE;
c_eol CONSTANT VARCHAR2(1) := CHR(10);
c_eollen CONSTANT PLS_INTEGER := LENGTH(c_eol);
c_maxline CONSTANT PLS_INTEGER := 32767;
BEGIN
--v_sid := lpad(sys_context('USERENV', 'sid'), 10, '0');
v_name:=p_filename;
LOOP
if utl_file.is_open(v_file)
then
utl_file.fclose(v_file);
end if;
v_file := UTL_FILE.FOPEN(p_directory, v_name, 'A', c_maxline);
FETCH p_source BULK COLLECT INTO v_rows LIMIT 100;
FOR i IN 1 .. v_rows.COUNT LOOP
IF LENGTH(v_buffer) + c_eollen + LENGTH(v_rows(i)) <= c_maxline THEN
v_buffer := v_buffer || c_eol || v_rows(i);
ELSE
IF v_buffer IS NOT NULL THEN
UTL_FILE.PUT_LINE(v_file, v_buffer);
END IF;
v_buffer := v_rows(i);
END IF;
END LOOP;
v_lines := v_lines + v_rows.COUNT;
EXIT WHEN p_source%NOTFOUND;
END LOOP;
CLOSE p_source;
UTL_FILE.PUT_LINE(v_file, v_buffer);
UTL_FILE.FCLOSE(v_file);
v_end_dttm := SYSTIMESTAMP;
--PIPE ROW (dump_ot(v_name, p_directory, v_lines, v_sid, v_start_dttm, v_end_dttm));
--RETURN ;
END;
我用这种方式调用函数。
SELECT * from table(DATA_UNLOAD(
CURSOR(select /*+ PARALLEL */ a || b || c from sample_table),
'sample.txt',
'99_DIR'));
我作为参数传递给函数的真实生活选择返回30000行,但是当我使用该函数将结果加载到文件中时,某些行会丢失。在使用PARALLEL提示执行期间,有24个并行会话,我不想减少它。我的猜测是问题在于并行执行,因为当我不使用PARALLEL提示时,没有数据丢失。如果没有删除提示,任何人都可以建议摆脱这个问题?
答案 0 :(得分:1)
即使您正在使用追加模式创建sample.txt,您也会有24个并行会话。我总是通过将SID附加到您的变量来使用唯一的文件名:
SELECT sid INTO v_sid FROM v$mystat WHERE ROWNUM = 1;
v_name := p_filename || '_' || v_sid || '.dat';
根据并行会话的数量,您应该使用格式为sample_ nnnn .txt的1到多个文件,其中 nnnn 是SID编号。