导出为插入语句:但在SQL Plus中,该行会覆盖2500个字符!

时间:2010-04-29 08:56:05

标签: oracle sqlplus

我必须将Oracle表导出为INSERT STATEMENTS。

但是生成的INSERT STATEMENTS会覆盖2500个字符。

我不得不在SQL Plus中执行它们,因此收到错误消息。

这是我的Oracle表:

CREATE TABLE SAMPLE_TABLE
(
   C01   VARCHAR2 (5 BYTE) NOT NULL,
   C02   NUMBER (10) NOT NULL,
   C03   NUMBER (5) NOT NULL,
   C04   NUMBER (5) NOT NULL,
   C05   VARCHAR2 (20 BYTE) NOT NULL,
   c06   VARCHAR2 (200 BYTE) NOT NULL,
   c07   VARCHAR2 (200 BYTE) NOT NULL,
   c08   NUMBER (5) NOT NULL,
   c09   NUMBER (10) NOT NULL,
   c10   VARCHAR2 (80 BYTE),
   c11   VARCHAR2 (200 BYTE),
   c12   VARCHAR2 (200 BYTE),
   c13   VARCHAR2 (4000 BYTE),
   c14   VARCHAR2 (1 BYTE) DEFAULT 'N' NOT NULL,
   c15   CHAR (1 BYTE),
   c16   CHAR (1 BYTE)
);

假设:

a)我有责任将表数据导出为INSERT STATEMENTS;我被允许使用UPDATE语句,以避免SQL * Plus错误“sp2-0027输入太长(> 2499个字符)”;

b)我有义务使用SQL * Plus来执行如此生成的脚本。

c)请假设每条记录都包含特殊字符:CHR(10),CHR(13)等;

d)我不能使用SQL Loader;

e)我无法导出然后导入表:我只能通过SQL Plus使用INSERT / UPDATE语句添加“delta”。

2 个答案:

答案 0 :(得分:6)

哇,这些限制是非常有限的,但我认为可能有办法绕过它。我认为你可能必须为此编写自己的小脚本。

我自己会使用Java和JDBC(但是任何可以连接并读取数据库并输出字符串的语言都可以),编写一个小程序来检索数据库中每一行的记录集。然后,对于每一行:

  • 使用完整数据构造一个insert语句。如果这小于2,000字节,则只需将其输出到文件并继续下一行。

  • 否则为每个字段创建一个insert语句,但将c13字段保留为''(空)。

  • 然后,只要您的c13input字符串大于2000个字符,就输出格式为"update tbl set c13 = c13 || '" + c13input.substring (0,2000) + "' where ..."的更新语句(追加接下来的2000个字符),然后执行{{1}从你的字符串中删除那些字符。

  • 一旦c13input = c13input.substring(2000)长度小于或等于2000个字符,只需输出一个最终更新,以便在最后添加。

这允许您将各个SQL语句保持在2000个字符的标记周围,并有效地执行正确的SQL以重新填充另一个数据库表。

这是我正在谈论的事情类型(对于只包含主键c13input和一个大的honkin'varchar c1的表):

c13

显然,您可能需要对字符串进行变形以允许插入特殊字符 - 我不确定Oracle期望这些格式是什么格式,但希望传递字符串很简单(rowset r = db.exec ("select * from oldtable"); while r.next != NO_MORE_ROWS: string s = "insert into newtable (c1,c13) values ('" + r.get("c1") + "','" + r.get("c13") + "')" if s.len() < 2000: print s else: s = "insert into newtable (c1,c13) values ('" + r.get("c1") + "','')" print s f = r.get("c13") while f.len() > 2000: s = "update newtable set c13 = c13 || '" + f.substring(0,2000) + ')" f = f.substring(2000) print s endwhile s = "update newtable set c13 = c13 || '" + f + ')" print s endif endwhile 如果完整插入的长度小于2000 r.get("c13")f.substring(0,2000)(如果你正在构建更新)到辅助函数来执行此操作。

如果该变形可能会增加打印行的大小,您可能希望将阈值降回1000以确保安全,以确保变形字符串不会导致大于PL / SQL限制的行

很抱歉,如果这看起来很复杂,但你所说的限制会让我们陷入困境。可能有更好的方法,但我想不出符合所有标准的方法。


更新:看起来你甚至更多陷入困境:如果你必须限制自己使用SQL来生成脚本除了运行它之外,有一种方式,虽然它是折磨的。

您可以使用SQL生成SQL。使用我上面提到的fc1表格,您可以执行以下操作:

c13

这将为您提供所有基线select 'insert into newtable (c1,c13) values ("' || c1 || '","");' from oldtable; # Xlates to: insert into newtable (c1,c13) values ("[c1]",""); 语句,用于复制除insert列之外的所有内容。

您需要做的是生成更多用于设置c13的语句。要更新c13所有长度为1000或更短的值(简单集):

c13

然后,select 'update newtable set c13 = "' || c13 || '" where c1 = "' || c1 || '";' from oldtable where length(c13) <= 1000; # Xlates to: update newtable set c13 = "[c13]" where c1 = "[c1]"; # but only for rows where length([c13]) <= 1000 c13为1001到2000个字符之间的所有值(然后设置追加):

update

对于那些长度为2001到3000和3001到4000的那些。

可能需要进行一些调整。我很乐意为你提供解决问题的方法,但我渴望完成这样一个怪物直到完成的愿望充其量只是: - )

它能完成工作吗?是。它漂亮吗?我会说这是一个响亮的“不!”但是,考虑到你的限制,这可能是你所希望的最好的。


作为概念证明,这里是DB2中的一个SQL脚本(虽然没有特殊功能,但它应该在任何具有select 'update newtable set c13 = "' || substring(c13,1,1000) || '" where c1 = "' || c1 || '";' from oldtable where length(c13) > 1000 and length(c13) <= 2000; select 'update newtable set c13 = c13 || "' || substring(c13,1001,1000) || '" where c1 = "' || c1 || '";' from oldtable where length(c13) > 1000 and length(c13) <= 2000; # Xlates to: update newtable set c13 = "[c13a]" where c1 = "[c1]"; # update newtable set c13 = c13 || "[c13b]" where c1 = "[c1]"; # but only for rows where length([c13]) > 1000 and <= 2000 # and [c13a]/[c13b] are the first/second thousand chars of c13. length等效的DBMS中正常工作:

substr

这将生成以下行:

# Create table and populate.

DROP TABLE XYZ;
COMMIT;
CREATE TABLE XYZ (F1 VARCHAR(1),F2 VARCHAR(20));
COMMIT;
INSERT INTO XYZ VALUES ('1','PAX');
INSERT INTO XYZ VALUES ('2','GEORGE');
INSERT INTO XYZ VALUES ('3','VLADIMIR');
INSERT INTO XYZ VALUES ('4','ALEXANDRETTA');
SELECT * FROM XYZ ORDER BY F1;

# Create initial insert statem,ents.

SELECT 'INSERT INTO XYZ (F1,F2) VALUES (' || F1 ','''');' 
    FROM XYZ;

# Updates for 1-5 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || F2 ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) <= 5;

# Updates for 6-10 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;

# Updates for 11-15 character F2 fields.

SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6,5) ||
    ''' WHERE F1 = ''' || F1 || ''';'
  FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,11) || 
    ''' WHERE F1 = ''' || F1 || ''';'
    FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;

打破输出线,我们得到:

> DROP TABLE XYZ;
> COMMIT;
> CREATE TABLE XYZ (F1 VARCHAR(1),F2 VARCHAR(20));
> COMMIT;
> INSERT INTO XYZ VALUES ('1','PAX');
> INSERT INTO XYZ VALUES ('2','GEORGE');
> INSERT INTO XYZ VALUES ('3','VLADIMIR');
> INSERT INTO XYZ VALUES ('4','ALEXANDRETTA');
> SELECT * FROM XYZ;
    F1  F2
    --  ------------
    1   PAX
    2   GEORGE
    3   VLADIMIR
    4   ALEXANDRETTA

> SELECT 'INSERT INTO XYZ (F1,F2) VALUES (' || F1 || ','''');'
> FROM XYZ;
    INSERT INTO XYZ (F1,F2) VALUES (1,'');
    INSERT INTO XYZ (F1,F2) VALUES (2,'');
    INSERT INTO XYZ (F1,F2) VALUES (3,'');
    INSERT INTO XYZ (F1,F2) VALUES (4,'');

> SELECT 'UPDATE XYZ SET F2 = ''' || F2 ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) <= 5;
    UPDATE XYZ SET F2 = 'PAX' WHERE F1 = '1';

> SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;
    UPDATE XYZ SET F2 = 'GEORG' WHERE F1 = '2';
    UPDATE XYZ SET F2 = 'VLADI' WHERE F1 = '3';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 5 AND LENGTH(F2) <= 10;
    UPDATE XYZ SET F2 = F2 || 'E' WHERE F1 = '2';
    UPDATE XYZ SET F2 = F2 || 'MIR' WHERE F1 = '3';

> SELECT 'UPDATE XYZ SET F2 = ''' || SUBSTR(F2,1,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = 'ALEXA' WHERE F1 = '4';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,6,5) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = F2 || 'NDRET' WHERE F1 = '4';

> SELECT 'UPDATE XYZ SET F2 = F2 || ''' || SUBSTR(F2,11) ||
> ''' WHERE F1 = ''' || F1 || ''';'
> FROM XYZ WHERE LENGTH(F2) > 10 AND LENGTH(F2) <= 15;
    UPDATE XYZ SET F2 = F2 || 'TA' WHERE F1 = '4';

它应该为您提供原始行,尽管是以迂回的方式。


这就是我可以在没有大脑煎炸的情况下投入任何一个问题的努力,所以除非向我指出任何严重的错误,否则我会向你提出申请。

祝你的项目好运,并祝福。

答案 1 :(得分:1)

您可以使用Jailer工具(http://jailer.sf.net)将表数据导出为INSERT STATEMENTS。