所以我有一个查询,我想通过存储过程执行并将查询的输出导出到CSV文件。所以我使用以下存储过程来执行此操作:
CREATE OR REPLACE PROCEDURE parseCSV(
p_file_dir VARCHAR2, -- Oracle directory name
p_file_name VARCHAR2, -- filename
p_sql_query VARCHAR2, -- select * from table or some such query
p_delimiter CHAR -- column delimiter
)
AS
l_cursor_handle INTEGER;
l_dummy NUMBER;
l_col_cnt INTEGER;
l_rec_tab DBMS_SQL.DESC_TAB;
l_current_col NUMBER(16);
l_current_line VARCHAR2(2047);
l_column_value VARCHAR2(300);
l_file_handle UTL_FILE.FILE_TYPE;
l_print_text VARCHAR2(100);
l_record_count NUMBER(16) := 0;
BEGIN
l_file_handle := UTL_FILE.FOPEN(p_file_dir, p_file_name, 'a', 2047);
l_cursor_handle := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(l_cursor_handle, p_sql_query, DBMS_SQL.native);
l_dummy := DBMS_SQL.EXECUTE(l_cursor_handle);
DBMS_SQL.DESCRIBE_COLUMNS(l_cursor_handle, l_col_cnt, l_rec_tab);
l_current_col := l_rec_tab.FIRST;
IF (l_current_col IS NOT NULL) THEN
LOOP
DBMS_SQL.DEFINE_COLUMN(l_cursor_handle, l_current_col, l_column_value, 300);
l_print_text := l_rec_tab(l_current_col).col_name || p_delimiter;
UTL_FILE.PUT (l_file_handle, l_print_text);
l_current_col := l_rec_tab.NEXT(l_current_col);
EXIT WHEN (l_current_col IS NULL);
END LOOP;
END IF;
UTL_FILE.PUT_LINE (l_file_handle,' ');
LOOP
EXIT WHEN DBMS_SQL.FETCH_ROWS(l_cursor_handle) = 0;
l_current_line := '';
FOR l_current_col IN 1..l_col_cnt LOOP
DBMS_SQL.COLUMN_VALUE (l_cursor_handle, l_current_col, l_column_value);
l_print_text := l_column_value || p_delimiter;
l_current_line := l_current_line || l_column_value || p_delimiter;
END LOOP;
l_record_count := l_record_count + 1;
UTL_FILE.PUT_LINE (l_file_handle, l_current_line);
END LOOP;
UTL_FILE.FCLOSE (l_file_handle);
DBMS_SQL.CLOSE_CURSOR(l_cursor_handle);
END;
/
执行时的过程处理查询,然后将结果存储到分隔文件中。例如,常规SELECT语句的过程输出将采用以下形式:
ID,ROLL_NO,RANK,
1,123456,1620,
2,987654,1344,
现在这就是我的问题。正如您所看到的,输出文件中的每一行都以一个额外的尾随,
结束。现在,由于我对plsql缺乏了解,我无法想到我可以对该过程进行的修改,以便预期的输出文件具有以下形式:
ID,ROLL_NO,RANK
1,123456,1620
2,987654,1344
有人可以在这里帮助一个甲骨文新手并给我一些关于如何做到这一点的指示吗?我会非常感激。
答案 0 :(得分:0)
尝试此程序:
CREATE OR REPLACE PROCEDURE parseCSV(
p_file_dir VARCHAR2, -- Oracle directory name
p_file_name VARCHAR2, -- filename
p_sql_query VARCHAR2, -- select * from table or some such query
p_delimiter CHAR -- column delimiter
)
AS
l_cursor_handle INTEGER;
l_dummy NUMBER;
l_col_cnt INTEGER;
l_rec_tab DBMS_SQL.DESC_TAB;
l_current_col NUMBER(16);
l_current_line VARCHAR2(2047);
l_column_value VARCHAR2(300);
l_file_handle UTL_FILE.FILE_TYPE;
l_print_text VARCHAR2(100);
l_record_count NUMBER(16) := 0;
BEGIN
l_file_handle := UTL_FILE.FOPEN(p_file_dir, p_file_name, 'a', 2047);
l_cursor_handle := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(l_cursor_handle, p_sql_query, DBMS_SQL.native);
l_dummy := DBMS_SQL.EXECUTE(l_cursor_handle);
DBMS_SQL.DESCRIBE_COLUMNS(l_cursor_handle, l_col_cnt, l_rec_tab);
l_current_col := l_rec_tab.FIRST;
IF (l_current_col IS NOT NULL) THEN
LOOP
DBMS_SQL.DEFINE_COLUMN(l_cursor_handle, l_current_col, l_column_value, 300);
IF l_print_text IS NOT NULL THEN
l_print_text := l_print_text || p_delimiter;
END IF;
l_print_text := l_rec_tab(l_current_col).col_name;
UTL_FILE.PUT (l_file_handle, l_print_text);
l_current_col := l_rec_tab.NEXT(l_current_col);
EXIT WHEN (l_current_col IS NULL);
END LOOP;
END IF;
UTL_FILE.PUT_LINE (l_file_handle,' ');
l_print_text := NULL;
LOOP
EXIT WHEN DBMS_SQL.FETCH_ROWS(l_cursor_handle) = 0;
l_current_line := '';
FOR l_current_col IN 1..l_col_cnt LOOP
DBMS_SQL.COLUMN_VALUE (l_cursor_handle, l_current_col, l_column_value);
IF l_print_text IS NOT NULL THEN
l_print_text := l_print_text || p_delimiter;
END IF;
l_print_text := l_column_value;
END LOOP;
l_record_count := l_record_count + 1;
UTL_FILE.PUT_LINE (l_file_handle, l_print_text );
END LOOP;
UTL_FILE.FCLOSE (l_file_handle);
DBMS_SQL.CLOSE_CURSOR(l_cursor_handle);
END;
答案 1 :(得分:0)
首先,我要说导出CSV文件的程序应该命名为createCSV
,makeCSV
或类似名称,但绝不能parseCSV
。
接下来,我不确定这个应用程序设计是否最佳。通常,当外部客户端考虑媒体,格式等时,数据库应该担心数据。
最后,为了消除尾随分隔符,你应该使用这样的东西:
...
p_delimiter CHAR -- column delimiter
)
AS
l_delimiter varchar2(1 char);
...
BEGIN
....
l_current_col := l_rec_tab.FIRST;
l_delimiter := '';
....
l_print_text := l_delimiter || l_rec_tab(l_current_col).col_name;
l_delimiter := p_delimiter;
....
/
答案 2 :(得分:0)
请尝试以下添加评论的地方
CREATE OR REPLACE PROCEDURE parseCSV(
p_file_dir VARCHAR2, -- Oracle directory name
p_file_name VARCHAR2, -- filename
p_sql_query VARCHAR2, -- select * from table or some such query
p_delimiter CHAR -- column delimiter
)
AS
l_cursor_handle INTEGER;
l_dummy NUMBER;
l_col_cnt INTEGER;
l_rec_tab DBMS_SQL.DESC_TAB;
l_current_col NUMBER(16);
l_current_line VARCHAR2(2047);
l_column_value VARCHAR2(300);
l_file_handle UTL_FILE.FILE_TYPE;
l_print_text VARCHAR2(100);
l_record_count NUMBER(16) := 0;
BEGIN
l_file_handle := UTL_FILE.FOPEN(p_file_dir, p_file_name, 'a', 2047);
l_cursor_handle := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(l_cursor_handle, p_sql_query, DBMS_SQL.native);
l_dummy := DBMS_SQL.EXECUTE(l_cursor_handle);
DBMS_SQL.DESCRIBE_COLUMNS(l_cursor_handle, l_col_cnt, l_rec_tab);
l_current_col := l_rec_tab.FIRST;
IF (l_current_col IS NOT NULL) THEN
LOOP
DBMS_SQL.DEFINE_COLUMN(l_cursor_handle, l_current_col, l_column_value, 300);
l_print_text := l_rec_tab(l_current_col).col_name ||
p_delimiter;
l_current_col := l_rec_tab.NEXT(l_current_col);
IF l_current_col IS NULL/*handling for last delimiter for
column */
THEN
l_print_text:=substr(l_print_text,-1);
END IF;
UTL_FILE.PUT (l_file_handle, l_print_text);
EXIT WHEN (l_current_col IS NULL);
END LOOP;
END IF;
UTL_FILE.PUT_LINE (l_file_handle,' ');
LOOP
EXIT WHEN DBMS_SQL.FETCH_ROWS(l_cursor_handle) = 0;
l_current_line := '';
FOR l_current_col IN 1..l_col_cnt LOOP
DBMS_SQL.COLUMN_VALUE (l_cursor_handle, l_current_col, l_column_value);
l_print_text := l_column_value || p_delimiter;
IF l_current_col =l_col_cnt
then
l_current_line := l_current_line || l_column_value;
ELSE
l_current_line := l_current_line || l_column_value ||
p_delimiter;
END IF;
END LOOP;
l_record_count := l_record_count + 1;
UTL_FILE.PUT_LINE (l_file_handle, l_current_line);
END LOOP;
UTL_FILE.FCLOSE (l_file_handle);
DBMS_SQL.CLOSE_CURSOR(l_cursor_handle);
END;
答案 3 :(得分:0)
你可以做两件事。第一种是更新对UTL_FILE.put的调用,以便有条件地添加分隔符(下面的示例为标题记录,但同样可以应用于数据):
;
第二种方法是构建一个包含完整数据行的字符串,然后在调用UTL FILE之前操作该字符串(在这种情况下,我假设l_print_text对于一行数据足够长):
IF l_current_col < l_rec_tab.LAST THEN
l_print_text := l_rec_tab(l_current_col).col_name || p_delimiter;
ELSE
l_print_text := l_rec_tab(l_current_col).col_name ;
END IF ;
UTL_FILE.PUT (l_file_handle, l_print_text);
答案 4 :(得分:0)
我已经改变了你的代码。用户此程序:
CREATE OR REPLACE PROCEDURE PARSECSV
(
P_FILE_DIR VARCHAR2, -- Oracle directory name
P_FILE_NAME VARCHAR2, -- filename
P_SQL_QUERY VARCHAR2, -- select * from table or some such query
P_DELIMITER CHAR -- column delimiter
) IS
L_CURSOR_HANDLE INTEGER;
L_DUMMY NUMBER;
L_COL_CNT INTEGER;
L_REC_TAB DBMS_SQL.DESC_TAB;
L_COLUMN_VALUE VARCHAR2(300);
L_FILE_HANDLE UTL_FILE.FILE_TYPE;
L_PRINT_TEXT CLOB;
BEGIN
L_FILE_HANDLE := UTL_FILE.FOPEN(P_FILE_DIR,
P_FILE_NAME,
'a',
2047);
L_CURSOR_HANDLE := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(L_CURSOR_HANDLE,
P_SQL_QUERY,
DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS(L_CURSOR_HANDLE,
L_COL_CNT,
L_REC_TAB);
FOR L_CURRENT_COL IN 1 .. L_COL_CNT
LOOP
DBMS_SQL.DEFINE_COLUMN(L_CURSOR_HANDLE,
L_CURRENT_COL,
L_COLUMN_VALUE,
300);
IF L_PRINT_TEXT IS NOT NULL THEN
L_PRINT_TEXT := L_PRINT_TEXT || P_DELIMITER;
END IF;
L_PRINT_TEXT := L_PRINT_TEXT || L_REC_TAB(L_CURRENT_COL).COL_NAME;
END LOOP;
L_PRINT_TEXT := L_PRINT_TEXT || CHR(10) || CHR(13);
UTL_FILE.PUT(L_FILE_HANDLE,
L_PRINT_TEXT);
L_PRINT_TEXT := NULL;
L_DUMMY := DBMS_SQL.EXECUTE(L_CURSOR_HANDLE);
DBMS_OUTPUT.PUT_LINE(L_DUMMY);
LOOP
EXIT WHEN DBMS_SQL.FETCH_ROWS(L_CURSOR_HANDLE) = 0;
FOR L_CURRENT_COL IN 1 .. L_COL_CNT
LOOP
DBMS_SQL.COLUMN_VALUE(L_CURSOR_HANDLE,
L_CURRENT_COL,
L_COLUMN_VALUE);
IF L_PRINT_TEXT IS NOT NULL THEN
L_PRINT_TEXT := L_PRINT_TEXT || P_DELIMITER;
END IF;
L_PRINT_TEXT := L_PRINT_TEXT || L_COLUMN_VALUE;
END LOOP;
L_PRINT_TEXT := L_PRINT_TEXT || CHR(10) || CHR(13);
UTL_FILE.PUT(L_FILE_HANDLE,
L_PRINT_TEXT);
END LOOP;
UTL_FILE.FCLOSE(L_FILE_HANDLE);
DBMS_SQL.CLOSE_CURSOR(L_CURSOR_HANDLE);
END;
答案 5 :(得分:0)
首先,在数据库中创建一个目录,并提供对该目录的读写访问权限。
要创建目录:
CREATE OR REPLACE DIRECTORY alias AS 'pathname';
要授予阅读权限,请写:
GRANT read,write ON DIRECTORY alias TO {user | role | PUBLIC};
然后,使用下面的存储过程获取任何文件格式的SQL查询的输出。
CREATE OR REPLACE PROCEDURE CSV_EXPORT AS
CURSOR c_data IS
SELECT * from table_name;
v_file UTL_FILE.FILE_TYPE;
BEGIN
v_file := UTL_FILE.FOPEN(location => 'FILES1',
filename => 'csv_exp.txt',
open_mode => 'w',
max_linesize => 32767);
FOR cur_rec IN c_data LOOP
UTL_FILE.PUT_LINE(v_file,
cur_rec.column1 || ',' ||
cur_rec.column2 );
END LOOP;
UTL_FILE.FCLOSE(v_file);
EXCEPTION
WHEN OTHERS THEN
UTL_FILE.FCLOSE(v_file);
RAISE;
END;
要运行存储过程:
EXEC CSV_EXPORT;
代码FILES1中的目录名称。