Oracle SQL-使用INSERT INTO锁定行

Oracle SQL-使用INSERT INTO锁定行,sql,oracle,plsql,locking,Sql,Oracle,Plsql,Locking,我在Oracle SQL中遇到了以下问题。gt_general2是一个全局临时表 INSERT INTO gt_general2 (n_1, n_2, n_3) select p.x_id, a.y_id, a.dollar_amt from table_P p, table_A a where p.x_id = a.x_id and a.h_date = i_date and a.dollar_amt > 0 for update of p.x_id, a.dollar_amt

我在Oracle SQL中遇到了以下问题。gt_general2是一个全局临时表

INSERT INTO gt_general2 (n_1, n_2, n_3)
select p.x_id, a.y_id, a.dollar_amt
from table_P p, table_A a
where p.x_id = a.x_id
  and a.h_date = i_date
  and a.dollar_amt > 0
for update of p.x_id, a.dollar_amt nowait; --this is the problem statement
Oracle不喜欢我尝试将INSERT…SELECT语法与SELECT。。。对于语法。 我希望在执行此插入操作时锁定行,因为实际查询实际上相当复杂(并对其他视图执行一些检查以确保父记录存在,等等),这样我可以在执行单次行锁定操作时插入临时表

有没有其他语法让我可以这么做?在概念层面上,我看不出Oracle为什么不允许我从表P和a中选择行,在过程中锁定行,并将值插入另一个表Z中。毕竟,我已经可以做到这一点了:

select p.x_id, a.y_id
BULK COLLECT into x_id_list, y_id_list
from table_P, table_A
where ...
for update nowait;

当然,可以通过两次执行此查询来锁定行—一次锁定,一次插入。之前,我这样做了,并使用锁查询检索数组中的“x_id”值,以帮助插入到查询中。但我遇到的问题是x_id值不足以正确识别我想要的行;我需要一对(x_id,y_id),无法创建新的嵌套表类型来存储它

这取决于你为什么要这样做

如果您需要在事务开始时而不是在每个查询开始时访问行中的值,无论它们是否更改,那么我将研究更改会话,将读取一致性模式更改为“serializable”,而不是默认的“read committed”


如果您真的要回去更新这些行,那么我将考虑使用公共表表达式(CTE)而不是全局临时表,将所有逻辑封装在一个查询中。在许多情况下,GTT和CTE的优化效果几乎相同,尽管您当然不能在流程的中途对CTE进行分析,也不能对其创建索引。

这取决于您为什么要这样做

如果您需要在事务开始时而不是在每个查询开始时访问行中的值,无论它们是否更改,那么我将研究更改会话,将读取一致性模式更改为“serializable”,而不是默认的“read committed”


如果您真的要回去更新这些行,那么我将考虑使用公共表表达式(CTE)而不是全局临时表,将所有逻辑封装在一个查询中。在许多情况下,GTT和CTE的优化效果几乎相同,尽管您当然不能在流程的一部分对CTE进行分析,也不能对其创建索引。

您不能在单个语句中组合
插入
选择更新
。但是,您可以使用常规的
选择进行更新
,并将批量收集与批量插入结合使用,以实现几乎相似的性能

如果在PL/SQL代码中声明集合,也不需要创建新的永久SQL类型对象

下面是一个示例,首先是设置:

SQL> CREATE TABLE table_a (x_id NUMBER, y_id NUMBER, dollar_amt NUMBER);
Table created
SQL> CREATE TABLE table_p (x_id NUMBER);
Table created
SQL> INSERT INTO table_a VALUES (1, 1, 0);
1 row inserted
SQL> INSERT INTO table_a VALUES (2, 1, 10);
1 row inserted
SQL> INSERT INTO table_a VALUES (3, 1, 20);
1 row inserted
SQL> INSERT INTO table_p VALUES (2);
1 row inserted
SQL> INSERT INTO table_p VALUES (3);
1 row inserted
SQL> INSERT INTO table_p VALUES (4);
1 row inserted
SQL> CREATE GLOBAL TEMPORARY TABLE gt_general2(
  2     n_1 NUMBER, 
  3     n_2 NUMBER, 
  4     n_3 NUMBER);
Table created
锁定和插入程序(在11.2.0.2.0中测试):


这将在一次过程中批量选择/插入100行。这应该比紧跟insert语句的lock语句快。此外,还可以保证插入的行与锁定的行完全相同(而如果表被修改,则一个接一个执行的两条语句可能会返回不一致的结果)

不能在一条语句中将
INSERT
SELECT FOR UPDATE
组合在一起。但是,您可以使用常规的
选择进行更新
,并将批量收集与批量插入结合使用,以实现几乎相似的性能

如果在PL/SQL代码中声明集合,也不需要创建新的永久SQL类型对象

下面是一个示例,首先是设置:

SQL> CREATE TABLE table_a (x_id NUMBER, y_id NUMBER, dollar_amt NUMBER);
Table created
SQL> CREATE TABLE table_p (x_id NUMBER);
Table created
SQL> INSERT INTO table_a VALUES (1, 1, 0);
1 row inserted
SQL> INSERT INTO table_a VALUES (2, 1, 10);
1 row inserted
SQL> INSERT INTO table_a VALUES (3, 1, 20);
1 row inserted
SQL> INSERT INTO table_p VALUES (2);
1 row inserted
SQL> INSERT INTO table_p VALUES (3);
1 row inserted
SQL> INSERT INTO table_p VALUES (4);
1 row inserted
SQL> CREATE GLOBAL TEMPORARY TABLE gt_general2(
  2     n_1 NUMBER, 
  3     n_2 NUMBER, 
  4     n_3 NUMBER);
Table created
锁定和插入程序(在11.2.0.2.0中测试):


这将在一次过程中批量选择/插入100行。这应该比紧跟insert语句的lock语句快。此外,还可以保证插入的行与锁定的行完全相同(而如果表被修改,则一个接一个执行的两条语句可能会返回不一致的结果)

第二种情况-过程是1)通过查询查找核心表中的行并锁定它们以进行更新,2)将从这些行派生的一组值插入临时表,3)通过光标在临时表中的美元金额之间执行大量重新分配计算,4)使用临时表还存储父序列NEXTVAL值,以供子记录访问,并插入到单独的事务日志表中;5)返回并使用新值更新核心表。我尝试使用WITH()表,但过程太复杂,无法发挥多大作用。第二种情况是:1)通过查询查找核心表中的行并锁定它们以进行更新,2)将从这些行派生的一组值插入临时表,3)通过光标在临时表中的美元金额之间执行大量重新分配计算,4)使用临时表还存储父序列NEXTVAL值以供子记录访问,并插入到单独的事务日志表中,5)返回并用新值更新核心表。我尝试使用WITH()表,但过程太复杂,它们没有多大用处。“无法创建新的嵌套表类型来存储它”。。。由于技术限制或特权,“无法创建新的嵌套表类型来存储它”。。。因为技术限制或特权?嘿,谢谢你的建议。不过,我遇到了一个问题。它编译得很好,但在我运行它时发生了崩溃:错误从命令中的第7行开始