在Oracle中使用UTF_FILE
是我的新手。我有一个 CSV 文件,包含30万条记录和6列,这些列用逗号“,” 分隔。
我希望将所有这些数据拆分并设置为某些变量,并通过Pl / SQL插入到某些表或列中,但是我该怎么做呢?
目前,执行pl / sql的时间并不重要 [Oracle 11gR2 XE]
答案 0 :(得分:1)
您要解决的问题:
DECLARE
v_row VARCHAR2(200) := 'a,b,c';
BEGIN
FOR v_col IN (SELECT REGEXP_SUBSTR (v_row, '[^,]+', 1, LEVEL) cell FROM DUAL CONNECT BY REGEXP_SUBSTR (v_row, '[^,]+', 1, LEVEL) IS NOT NULL)
LOOP
DBMS_OUTPUT.PUT_LINE (v_col.cell);
END LOOP;
END;
但是,正如评论所说:您不应该这样做。使用SQL Loader:Oracle: Import CSV file
答案 1 :(得分:1)
嗨,我几年前已经使用过此代码,并且可以正常工作
您可以将其更改为使用regexp而不是复杂的 substr s
您可以使用索引表而不是我使用的嵌套表类型,可以将嵌套插入表中,但是 index-by 仅在pl / sql上可用,不能作为参数传递给其他存储的程序(可以嵌套)。
CREATE OR REPLACE TYPE ARRAY_OF_TEXTS AS TABLE OF VARCHAR2 (4000);
CREATE OR REPLACE TYPE ARRAY_OF_ARRAYS AS TABLE OF ARRAY_OF_TEXTS;
CREATE OR REPLACE FUNCTION SPLIT (
TEXT IN CLOB,
C_SEPARATOR IN VARCHAR2,
IGNORE_EMBTY_BLOCKS IN BOOLEAN DEFAULT FALSE)
RETURN ARRAY_OF_TEXTS
IS
S_LINE VARCHAR2 (4000);
S_TABLE ARRAY_OF_TEXTS;
I INTEGER;
OFFSET1 INTEGER := 1;
OFFSET2 INTEGER;
TEXT_LEN INTEGER;
BEGIN
S_TABLE := ARRAY_OF_TEXTS ();
OFFSET2 := INSTR (TEXT, C_SEPARATOR, OFFSET1);
TEXT_LEN := DBMS_LOB.GETLENGTH (TEXT);
IF OFFSET2 < 1 --if there is no c_separator (if offset2 is 0) or there is not any c_separator at the end of text
THEN
OFFSET2 := TEXT_LEN;
END IF;
WHILE (OFFSET2 = OFFSET1 + LENGTH (C_SEPARATOR) OR OFFSET2 = OFFSET1)
AND DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1) =
C_SEPARATOR -- if there are 2 c_separator sequentially
LOOP
IF NOT IGNORE_EMBTY_BLOCKS
THEN
S_TABLE.EXTEND;
S_TABLE (S_TABLE.LAST) := NULL;
END IF;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
END LOOP;
IF OFFSET2 > OFFSET1 + LENGTH (C_SEPARATOR)
THEN
S_TABLE.EXTEND;
S_LINE := DBMS_LOB.SUBSTR (TEXT, OFFSET2 - OFFSET1, OFFSET1);
S_TABLE (S_TABLE.LAST) := S_LINE;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
END IF;
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
WHILE OFFSET2 > 1
LOOP
S_TABLE.EXTEND;
S_LINE := DBMS_LOB.SUBSTR (TEXT, OFFSET2 - OFFSET1, OFFSET1);
S_TABLE (S_TABLE.LAST) := S_LINE;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
WHILE ( OFFSET2 = OFFSET1 + LENGTH (C_SEPARATOR)
OR OFFSET2 = OFFSET1)
AND DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1) =
C_SEPARATOR -- if there are 2 c_separator sequentially
LOOP
IF NOT IGNORE_EMBTY_BLOCKS
THEN
S_TABLE.EXTEND;
S_TABLE (S_TABLE.LAST) := NULL;
END IF;
OFFSET1 := OFFSET2 + LENGTH (C_SEPARATOR);
OFFSET2 := DBMS_LOB.INSTR (TEXT, C_SEPARATOR, OFFSET1);
END LOOP;
END LOOP;
IF OFFSET1 < TEXT_LEN
THEN
S_TABLE.EXTEND;
S_LINE :=
DBMS_LOB.SUBSTR (
TEXT,
TEXT_LEN - OFFSET1 + LENGTH (C_SEPARATOR),
OFFSET1
);
S_TABLE (S_TABLE.LAST) := S_LINE;
ELSIF OFFSET1 = TEXT_LEN
AND DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1) <>
C_SEPARATOR
THEN
S_TABLE.EXTEND;
S_LINE.TEXT := DBMS_LOB.SUBSTR (TEXT, LENGTH (C_SEPARATOR), OFFSET1);
S_TABLE (S_TABLE.LAST) := S_LINE;
END IF;
RETURN S_TABLE;
END;
CREATE OR REPLACE FUNCTION LOAD_CSV_FILE (
P_DIRECTORY IN VARCHAR2,
P_FILENAME IN VARCHAR2
)
RETURN ARRAY_OF_ARRAYS
AS
SEPARATOR1 VARCHAR2 (2) := CHR (10);
-- In Some Cases you should use: CHR (13) || CHR (10);
SEPARATOR2 VARCHAR2 (1) := ',';
--if csv separator is ; or | use it here
V_TEXT CLOB;
V_BFILE BFILE;
V_LINES ARRAY_OF_TEXTS;
V_LINE ARRAY_OF_TEXTS;
V_ARRAY ARRAY_OF_ARRAYS;
BEGIN
SELECT EMPTY_CLOB () INTO V_TEXT FROM DUAL;
--V_TEXT := EMPTY_CLOB ();
DBMS_LOB.CREATETEMPORARY(V_TEXT, TRUE);
V_BFILE := BFILENAME (P_DIRECTORY, P_FILENAME);
IF DBMS_LOB.FILEEXISTS (V_BFILE) <> 1
THEN
RETURN NULL;
END IF;
DBMS_LOB.FILEOPEN (V_BFILE, DBMS_LOB.FILE_READONLY);
DBMS_LOB.LOADFROMFILE (V_TEXT, V_BFILE, DBMS_LOB.GETLENGTH (V_BFILE));
DBMS_LOB.FILECLOSE (V_BFILE);
V_LINES := SPLIT2 (V_TEXT, SEPARATOR1);
V_ARRAY := ARRAY_OF_ARRAYS ();
FOR R_LINE IN (SELECT *
FROM TABLE (V_LINES))
LOOP
V_LINE := SPLIT(R_LINE.COLUMN_VALUE, SEPARATOR2);
V_ARRAY.EXTEND ();
V_ARRAY (V_ARRAY.LAST) := V_LINE;
END LOOP;
RETURN V_ARRAY;
END;
现在您可以像这样使用它:
DECLARE
V_ARR ARRAY_OF_ARRAYS;
V_LINE VARCHAR2 (4000);
BEGIN
V_ARR := LOAD_CSV_FILE ('MY_DIR', 'file.csv');
FOR LINE IN (SELECT *
FROM TABLE (V_ARR))
LOOP
FOR FIELD IN (SELECT *
FROM TABLE (LINE.COLUMN_VALUE))
LOOP
DBMS_OUTPUT.PUT_LINE ('field:' || FIELD.COLUMN_VALUE);
END LOOP;
DBMS_OUTPUT.PUT_LINE ('end of line');
END LOOP;
END;