【问题标题】:ORACLE - GENERATE INSERT STATEMENTORACLE - 生成插入语句
【发布时间】:2013-12-10 16:55:07
【问题描述】:

以下函数生成 SELECT 以生成 Oracle 表记录的 INSERT STATEMENT:

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 以生成 INSERT 语句。

如果在VARCHAR2 字段中的值以CHR(0) 结尾,则INSERT 语句将被截断,正好是CHR(0) 所在的位置。

我该如何解决这个问题?

【问题讨论】:

  • 您的意思是当您运行由函数生成的各个插入语句时,而不是在运行函数本身时,对吧? (只是出于兴趣,例如,您为什么要这样做而不是导出数据?)
  • 当我运行该功能时,一切正常。当我运行该函数生成的 SELECT 时,该函数会产生许多 INSERT STATEMENTS。其中一些 INSERT STATEMENTS 在某些 VARCHAR2 字段中存在 CHR(0) 时被截断。
  • 这不能回答您的问题,但您可能需要研究替代引用机制和时间戳文字,以帮助保持此类代码的清洁。例如:q'! ' !'timestamp '2000-01-01 14:00:00'

标签: oracle insert


【解决方案1】:

如果我理解您所看到的,您需要从值中去除空字符:

  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 的虚拟表,其中包含'hello' 的单列str 后跟一个空字符,输出为:

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 会简单得多。

【讨论】:

  • 非常感谢您的清晰解释。我更喜欢的方法当然是保留 NULL 字符 CHR(0),将其作为插入语句的一部分放回原处。再次感谢 ;-)
【解决方案2】:

使用这个:

用法:

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

您可以在这里找到原始源代码:

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-05
相关资源
最近更新 更多