2013-12-10 79 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