Oracle-如何动态创建一个具有多个值的插入

时间:2019-05-20 10:31:47

标签: oracle sqlplus

我想动态创建一个具有多个值的INSERT语句,如以下示例所示:

INSERT INTO table_name (ID, PARENT, NAME, ENABLED) 
VALUES (1, 't1', 'Test1', 1 ), (2, 't2', 'Test2', 1 ), (3, 't3', 'Test3', 1 );

当前,我正在使用以下语句,但是现在我得到的单个语句过多,因此无法提供良好的性能

SELECT 'INSERT INTO table_name(ID, PARENT, NAME, ENABLED) ' 
|| 'VALUES ('|| ID ||','''|| PARENT ||''','''|| NAME || ''', '|| ENABLED ||');'
FROM table_name WHERE ID IN (... [inner select] ...);

怎么可能在这样的单个插入语句中创建一个附加新值的循环?

SELECT 'INSERT INTO table_name (ID, PARENT, NAME, ENABLED)' VALUES

DECLARE
    myValues varchar2(500);
    CURSOR myCur IS SELECT ID, PARENT, NAME, ENABLED FROM table_name;
BEGIN
    FOR values IN myCur LOOP

        IF myCur%ROWCOUNT = 1 THEN
            myValues := '('||values.ID ||', '''|| values.PARENT ||''', '''|| values.NAME ||''', '|| values.ENABLED ||'),';
        ELSE
            myValues := '('||values.ID ||', '''|| values.PARENT ||''', '''|| values.NAME ||''', '|| values.ENABLED ||')';
        end if;
    END LOOP;
END;
--...

我需要使用SQLplus导出我的数据并将其插入另一个数据库

谢谢

3 个答案:

答案 0 :(得分:2)

如果要插入静态增量数据(按照您的原始示例),请对分层查询使用INSERT INTO ... SELECT

INSERT INTO table_name ( id, parent, name, enabled )
  SELECT LEVEL, 't' || LEVEL, 'Test' || LEVEL, 1
  FROM   DUAL
  CONNECT BY LEVEL <= 3

如果要从现有表构建查询,则:

SELECT 'INSERT INTO table_name ( id, parent, name, enabled )'
       || LISTAGG( 
            'SELECT ' || id || ', '
                    || '''' || REPLACE( parent, '''', '''''' ) || ''', '
                    || '''' || REPLACE( name, '''', '''''' ) || ''', '
                    || enabled
            || ' FROM DUAL',
            ' UNION ALL '
          ) WITHIN GROUP ( ORDER BY ROWNUM )
FROM   table_name

如果要超过4000个字符,则可以生成多行:

SELECT 'INSERT INTO table_name ( id, parent, name, enabled )' FROM DUAL
UNION ALL
SELECT 'SELECT ' || id || ', '
                 || '''' || REPLACE( parent, '''', '''''' ) || ''', '
                 || '''' || REPLACE( name, '''', '''''' ) || ''', '
                 || enabled
       || ' FROM DUAL'
       || CASE WHEN ROWNUM < COUNT(*) OVER () THEN ' UNION ALL ' END
FROM   table_name

db <>提琴here

或使用Oracle实用程序RMANExpDP生成表的备份。

答案 1 :(得分:0)

我认为,您应该停止重新发明轮子。 Oracle提供了数据泵导出/导入实用程序,这些实用程序旨在用于此目的-移动数据。在简单的(或者,我应该说大多数)情况下,甚至可以使用原始导出/导入实用程序。

您未指定要使用的数据库版本-这是12c数据泵文档:https://docs.oracle.com/database/121/SUTIL/GUID-501A9908-BCC5-434C-8853-9A6096766B5A.htm#SUTIL2877

有很多示例将展示如何做到这一点。我建议您不要跳过阅读文档,而直接跳到运行一些代码。了解自己的实际工作将使您受益,而不是希望它会变成 right

答案 2 :(得分:0)

一种方法是使用XML文件进行数据传输。

以XML格式获取数据:

DECLARE
  l_xml        DBMS_XMLGEN.ctxHandle;
BEGIN
  l_xml := dbms_xmlgen.newContext('SELECT * FROM table_name WHERE ID IN (... [inner select] ...)');
  dbms_output.put_line(dbms_xmlgen.getXML(l_xml));
  dbms_xmlgen.closeContext(l_xml);
END;

插入声明:

INSERT INTO table_name (ID, PARENT, NAME, ENABLED)
SELECT dbms_xmlgen.convert(value(soc).EXTRACT('/ROW/ID/text()'     ).getStringVal(), 1)
     , dbms_xmlgen.convert(value(soc).EXTRACT('/ROW/PARENT/text()' ).getStringVal(), 1)
     , dbms_xmlgen.convert(value(soc).EXTRACT('/ROW/NAME/text()'   ).getStringVal(), 1)
     , dbms_xmlgen.convert(value(soc).EXTRACT('/ROW/ENABLED/text()').getStringVal(), 1)
  FROM TABLE(XMLSequence(EXTRACT(XMLType(<XML>), '/ROWSET/ROW'))) SOC