2013-12-10 127 views
1

下面的函數產生SELECT以產生一個Oracle表的記錄插入語句:ORACLE - GENERATE INSERT語句

CREATE OR REPLACE FUNCTION GEN_INSERT_STATEMENT (IN_TABLE_NAME VARCHAR2) 
    RETURN CLOB 
IS 
    LC$COLS_SELECT CLOB; 
    LC$COLS_VALUES CLOB; 
    LC$COLOUMN  CLOB; 

    CURSOR LCUR$TAB_COLUMNS (IN_TABLE_NAME VARCHAR2) 
    IS 
     SELECT COLUMN_NAME, DATA_TYPE, COLUMN_ID 
      FROM USER_TAB_COLS 
     WHERE TABLE_NAME = IN_TABLE_NAME 
     ORDER BY COLUMN_ID; 
BEGIN 
    FOR LREC$TAB_COLUMNS IN LCUR$TAB_COLUMNS (UPPER (IN_TABLE_NAME)) 
    LOOP 
     LC$COLS_SELECT := 
      LC$COLS_SELECT 
     || CASE LREC$TAB_COLUMNS.COLUMN_ID WHEN 1 THEN '' ELSE ',' END 
     || LREC$TAB_COLUMNS.COLUMN_NAME; 

     IF INSTR (LREC$TAB_COLUMNS.DATA_TYPE, 'CHAR') > 0 
     THEN 
     LC$COLOUMN := 
       '''''''''||REPLACE(' 
      || LREC$TAB_COLUMNS.COLUMN_NAME 
      || ','''''''','''''''''''')||'''''''''; 
     ELSIF INSTR (LREC$TAB_COLUMNS.DATA_TYPE, 'DATE') > 0 
     THEN 
     LC$COLOUMN := 
      '''TO_DATE(''''''||TO_CHAR(' || LREC$TAB_COLUMNS.COLUMN_NAME 
      || ',''mm/dd/yyyy hh24:mi:ss'')||'''''',''''mm/dd/yyyy hh24:mi:ss'''')'''; 
     ELSE 
     LC$COLOUMN := LREC$TAB_COLUMNS.COLUMN_NAME; 
     END IF; 

     LC$COLS_VALUES := 
      LC$COLS_VALUES 
     || CASE LREC$TAB_COLUMNS.COLUMN_ID WHEN 1 THEN '' ELSE ',' END 
     || '''||DECODE(' 
     || LREC$TAB_COLUMNS.COLUMN_NAME 
     || ',NULL,''NULL'',' 
     || LC$COLOUMN 
     || ')||'''; 
    END LOOP; 

    RETURN 'SELECT ''INSERT INTO ' 
      || IN_TABLE_NAME 
      || ' (' 
      || LC$COLS_SELECT 
      || ') VALUES (' 
      || LC$COLS_VALUES 
      || ');'' FROM ' 
      || IN_TABLE_NAME 
      || ';'; 
END; 
/

的問題是,此功能不處理在其中現有的一些VARCHAR2的情況下用繩子領域結尾:CHR(0)

用法:

SELECT GEN_INSERT_STATEMENT ('MY_ORACLE_TABLE_NAME') FROM DUAL; 

...生成一個SELECT來produc e INSERT聲明。

如果在VARCHAR2字段中的值與CHR(0)結束後,INSERT語句將被截斷,究竟哪裏是CHR(0)位置。

我該如何解決這個問題?

+1

當您運行由函數生成的單個插入語句你的意思是,不是當您運行本身的功能,對不對? (出於興趣,爲什麼你會這樣做而不是導出數據,例如?) –

+0

當我運行該功能時,它是可以的。當我運行由該函數生成的SELECT時,函數會生成許多INSERT語句。其中一些INSERT語句在某些VARCHAR2字段內的CHR(0)存在的地方被截斷。 – UltraCommit

+2

這並不回答你的問題,但你可能想看看替代的引用機制和時間戳文字,以幫助保持這種類型的代碼乾淨。例如:'q'! '!''和'timestamp'2000-01-01 14:00:00''。 –

回答

2

如果我理解你所看到的,你需要無論是從價值剝離空字符:

IF INSTR (LREC$TAB_COLUMNS.DATA_TYPE, 'CHAR') > 0 
    THEN 
    LC$COLOUMN := 
      '''''''''||REPLACE(REPLACE(' 
     || LREC$TAB_COLUMNS.COLUMN_NAME 
     || ',CHR(0),NULL),'''''''','''''''''''')||'''''''''; 

這給你的函數的輸出:

SELECT 'INSERT INTO T42 (STR) VALUES ('||DECODE(STR,NULL,'NULL',''''||REPLACE(REPLACE(STR,CHR(0),NULL),'''','''''')||'''')||');' FROM T42; 

,並用假表格名爲t42,單列str包含'hello'後跟空字符,輸出爲:

INSERT INTO T42 (STR) VALUES ('Hello'); 

或插入過程中保護它:

 LC$COLOUMN := 
      '''''''''||REPLACE(REPLACE(' 
     || LREC$TAB_COLUMNS.COLUMN_NAME 
     || ','''''''',''''''''''''),CHR(0),''''''||CHR(0)||'''''')||'''''''''; 

這給:

SELECT 'INSERT INTO T42 (STR) VALUES ('||DECODE(STR,NULL,'NULL',''''||REPLACE(REPLACE(STR,'''',''''''),CHR(0),'''||CHR(0)||''')||'''')||');' FROM T42; 

最後:

INSERT INTO T42 (STR) VALUES ('Hello'||CHR(0)||''); 

所以在第二個版本的空字符從固定取出字符串(任何地方,不只是在最後),並作爲插入語句的一部分放回。

雖然這可能是一種可怕的方法,但您可以導出數據,或讓SQL Developer或其他IDE爲您生成插入語句。還有其他的數據類型和值讓你頭痛,而其他人已經努力克服。除非你真的需要看到實際的陳述,否則使用expdp會簡單得多。

+0

非常感謝您的明確解釋。我更喜歡的方法是保留NULL字符CHR(0),並將其作爲插入語句的一部分放回。再次感謝;-) – UltraCommit

1

使用此:

用法:

select fn_gen_inserts('select * from tablename', 'p_new_owner_name', 'p_new_table_name') 
from dual; 

其中:

p_sql   – dynamic query which will be used to export metadata rows 
p_new_owner_name – owner name which will be used for generated INSERT 
p_new_table_name – table name which will be used for generated INSERT 

您可以找到原始的源代碼H ERE:

+0

請閱讀[如何提供個人開源庫?](// meta.stackexchange.com/q/229085),並**明確表示這是您自己的項目**。 – robinCTS