使用 PL/SQL 使用 forall 语法批量插入

Posted

技术标签:

【中文标题】使用 PL/SQL 使用 forall 语法批量插入【英文标题】:Bulk insert with forall syntax using PL/SQL 【发布时间】:2018-03-26 07:43:16 【问题描述】:

我习惯使用 T-SQL,但目前我正在使用 PL/SQL 进行项目,因此语法有时会有点不同。

现在,我正在尝试在数据库中插入大约 5000 条记录。这将通过 12 个不同的连接发生。 (我有 12 个 XML 不同的 XML 文件,我想在相应的表中插入每个 XML 的所有数据)

我的第一个想法是为每个插入生成一个新的 INSERT INTO 查询,但我猜这会带来一些真正的性能问题。

接下来我读到了INSERT ALL INTO <table_name>,但我不确定这是否能解决性能问题?

最后,我读到FORALL 会在执行批量插入时显着提高速度。 (http://www.dba-oracle.com/oracle_news/news_plsql_forall_performance_insert.htm) 不幸的是,由于我的 PLSQL 知识还不是很好,所以我不知道如何解决这个问题。

我想做一些事情:

FORALL i IN 1..10
    INSERT INTO DELETEME (ID, NAME) VALUES (i, 'name' + i);

这是我的表结构:

ID      NUMBER(10,0)
NAME    VARCHAR2(255 BYTE)

这就是我得到的:

Error starting at line : 2 in command -
        INSERT INTO DELETEME (ID, NAME) VALUES (i, 'name' + i)
Error at Command Line : 2 Column : 61
Error report -
SQL Error: ORA-00984: column not allowed here
00984. 00000 -  "column not allowed here"
*Cause:    
*Action:

使用 FORALL 批量插入最简单的方法是什么? 或者你们知道有什么好的选择吗?

【问题讨论】:

【参考方案1】:

您的代码中有几个错误。一个是简单的语法错误,试试

... VALUES (i, 'name' || i);

在 Oracle 中,字符串由 || 连接,而不是由 +(也不是 &

除此之外,FORALL 用于 PL/SQL 表。可以这样运行

DECLARE
    TYPE nameTable IS TABLE OF INTEGER;
    names nameTable;
BEGIN   
    names := nameTable(10,20,30,40);
    FORALL i IN INDICES OF names
       INSERT INTO DELETEME (ID, NAME) VALUES (names(i), 'name' ||names(i) );   
END;

如果您只需要一个简单的序列,您也可以运行

INSERT INTO DELETEME (ID, NAME)
SELECT LEVEL, 'name' || LEVEL
FROM dual
CONNECT BY LEVEL <= 10;

【讨论】:

此时我遇到了两个错误。第一个声称在第 1 行有一个未知命令(FORALL i IN 1..10)。这可能是版本问题吗? 第二个错误表示第 59 列有错误(就在最后一个 i 之前和连接之后 (|| i)。说的和以前一样:这里不允许列。 来自 Oracle 文档:循环的每次迭代都必须在其 VALUES 或 WHERE 子句中使用来自一个或多个集合的值。 @Rene, names(i) 是“来自其 VALUES [...] 子句中的一个 [...] 集合的值” 设法让它与这个和 cmets 一起工作。以为我不明白为什么需要在 VALUES 子句中使用一个或多个集合的值。

以上是关于使用 PL/SQL 使用 forall 语法批量插入的主要内容,如果未能解决你的问题,请参考以下文章

Oracle pl/sql forall:如何计算表空间已满(1654)错误的实际插入行数

如何在 PL/SQL 中使用 BULK COLLECT 和 FORALL 替换 CURSOR FOR LOOP?

PL/SQL:语法错误

使用 FORALL 和 RETURNING 插入表时如何获取 ROWID

在 PL/SQL 中运行 forall 循环时,是不是需要事后提交?

Oracle 批量插入数据怎么做