我有以下代码:
DECLARE
TYPE table_invoice IS RECORD
(
invoiceId number(15),
status number(10),
);
TYPE invoice_data_table IS TABLE OF table_invoice;
invoice_data invoice_data_table;
BEGIN
select inv."InvoiceId",
inv."Status",
bulk collect
into invoice_data
from "Invoice" inv join "Company" c on inv."CompanyId" = c."Id"
where c."CompanyType" = 1
在这里我存储了选择数据,以便稍后用于更新和插入。不幸的是,批量更新不起作用。
Update "Invoice"
set "Status" = 200,
"LastModifiedDate" = (select sysdate from dual)
where "InvoiceId" in (select invoiceId from invoice_data); -- this select doesn't work, so the entire update will fail, why?
FOR i IN 1 .. invoice_data.count
LOOP
insert into "InvoiceStatusChange" ("Date", "NewStatus", "InvoiceId", "CompanyId")
select inv."InvoiceDate", inv."Status", inv."InvoiceId", inv."CompanyId" from "Invoice"
inv where "InvoiceId" = invoice_data(i).InvoiceId;
END LOOP;
END;
现在更新不起作用。只有当我移动到 for 循环并逐个更新记录时,它才有效,就像我对插入所做的那样。有没有一种方法可以一次性完成?与我尝试更新发票的方式类似,通过从缓存的invoice_data
传递id,使用“Invoice”表中的属性,从select语句插入 “Invoice” 表?就像这样:
insert into "InvoiceStatusChange" ("Date", "NewStatus", "InvoiceId", "CompanyId")
select inv."InvoiceDate", inv."Status", inv."InvoiceId", inv."CompanyId" from "Invoice"
inv where "InvoiceId" in (select invoiceId from invoice_data);
所以基本上,使用insert into select
语法通过传递一个ID列表,而不是一个接一个地传递?
2条答案
按热度按时间oo7oh9g91#
而不是
update
,尝试merge
。下面是一个基于Scott模式的例子;我在这里并没有做任何聪明的事情,只是为了说明如何做到这一点。在SQL级别创建类型:
这是初始表内容;我将更新
JOB
列的值:程序如下检查
using
子句(第10和11行):结果:
ie3xauqp2#
您可以使用
FORALL
语句从PL/SQL批量DML。它不需要新的模式级对象。对于loop
来说,这不是一个方便的快捷方式:它是纯批量装订。设置:
(批量)收集将更新的ID和before值,然后执行
forall
进行更新和插入:这导致:
但您可以优化访问。由于您使用额外的表只是为了过滤,因此值得通过
where
中的子查询显式地进行过滤:in
或exists
。Join是用来添加新信息的,过滤是它的一个副作用:当唯一的要求是过滤时,您显然不想关心键列和处理可能由联接产生的重复行。因此,将筛选移动到
where
中,您可以直接在具有returning
子句的update
语句中使用它,并且您也可以bulk collect
this。它将保存对同一表的一个额外访问:从update
而不是初步select
检索值。然后在附加表中执行相同的
forall
插入操作。这导致日志记录表的内容如下:
fiddle