Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在SQL中,如何使MERGE从一组返回的结果中用一行更新相关行_Sql_Oracle_Merge_Max_Correlated Subquery - Fatal编程技术网

在SQL中,如何使MERGE从一组返回的结果中用一行更新相关行

在SQL中,如何使MERGE从一组返回的结果中用一行更新相关行,sql,oracle,merge,max,correlated-subquery,Sql,Oracle,Merge,Max,Correlated Subquery,我使用MERGE(Oracle)对符合on子句中指定的条件的记录进行更新,on子句连接子查询创建的虚拟表。声明的格式如下: MERGE INTO table1 t1 USING SELECT (t2.f21, MAX(t2.f22), t3.f31, t3.f32 from table2 t2, table3 t3 where {... various join/filter criteria ...} group by t2.f21, t3.f31, t3.f32) MATCHDATA ON

我使用MERGE(Oracle)对符合on子句中指定的条件的记录进行更新,on子句连接子查询创建的虚拟表。声明的格式如下:

MERGE INTO table1 t1 USING SELECT (t2.f21, MAX(t2.f22), t3.f31, t3.f32 
from
table2 t2, table3 t3
where
{... various join/filter criteria ...}
group by t2.f21, t3.f31, t3.f32) MATCHDATA
ON (t1.f11 = MATCHDATA.f21)
where t1.f12 = 'something';
现在rub:MATCHDATA将返回多行,因为“…条件…”本质上将返回多组匹配记录。所以“groupby”和“MAX()”的使用并没有给我买任何担保;相反,如果我加上:

where rownum = 1
在将MATCHDATA结果包装在另一个SELECT语句中(该语句只是重复返回的字段名)之后,我将限制自己只能更新一组需要更新的记录中的一条记录,该记录具有由MAX()确定的最高值。相反,我需要更新表1中与其记录组的每个MAX()记录中的join字段相匹配的记录。我从周五开始。我是新来的,所以没有什么进展。但这看起来很有希望,也许明天会产生更好的结果。事实上,当我尝试使用它时,例如不使用“rownum=1”将MATCHDATA中返回的记录集限制为一条记录,我发现了一个熟悉的“无法返回稳定的记录集”错误,合并支持者(如我自己)在其同事向他们寻求建议时必须害羞地微笑“比相关子查询更好”-福音化的新SQL命令,因为它们面临同样的错误

如您所见,我将MERGE视为相关子查询的更成功的兄弟。但是,在这种情况下,我是否应该回顾两个象鼻虫中较小的一个(即,使用相关子查询)来完成工作?或者是通过分区或对上面的其他修改来找到修复

感谢所有花时间提供建议的人,我对此表示感谢

我得到了熟悉的“无法返回一组稳定的记录”错误

因为您在ON子句中使用的连接键不足以使行唯一,无法执行WHEN MATCHED THEN UPDATE语句。

必须在ON子句中包含更多的键,直到匹配的行是唯一的,从而返回一组稳定的记录

让我们看一个测试用例:

设置

SQL> CREATE TABLE source_table (
  2      col1 NUMBER,
  3      col2 VARCHAR2(10),
  4      col3 VARCHAR2(10)
  5  );

Table created.

SQL>
SQL> INSERT INTO source_table (col1, col2, col3) VALUES (1, 'a', 'p');

1 row created.

SQL> INSERT INTO source_table (col1, col2, col3) VALUES (1, 'b', 'q');

1 row created.

SQL> INSERT INTO source_table (col1, col2, col3) VALUES (2, 'c', 'r');

1 row created.

SQL> INSERT INTO source_table (col1, col2, col3) VALUES (3, 'c', 's');

1 row created.

SQL>
SQL> COMMIT;

Commit complete.

SQL>
SQL> CREATE TABLE target_table (
  2      col1 NUMBER,
  3      col2 VARCHAR2(10),
  4      col3 VARCHAR2(10)
  5  );

Table created.

SQL>
SQL> INSERT INTO target_table (col1, col2, col3) VALUES (1, 'b', 'p');

1 row created.

SQL> INSERT INTO target_table (col1, col2, col3) VALUES (3, 'd', 'q');

1 row created.

SQL>
SQL> COMMIT;

Commit complete.

SQL>
SQL> SELECT * FROM source_table;

      COL1 COL2       COL3
---------- ---------- ----------
         1 a          p
         1 b          q
         2 c          r
         3 c          s

SQL> SELECT * FROM target_table;

      COL1 COL2       COL3
---------- ---------- ----------
         1 b          p
         3 d          q

SQL>
错误再现

SQL> MERGE INTO target_table trg
  2  USING source_table src
  3  ON (trg.col1 = src.col1) -- Not Unique
  4  WHEN MATCHED THEN UPDATE SET
  5      trg.col2 = src.col2,
  6      trg.col3 = src.col3
  7  WHEN NOT MATCHED THEN INSERT
  8      (
  9          col1,
 10          col2,
 11          col3
 12      )
 13      VALUES
 14      (
 15          src.col1,
 16          src.col2,
 17          src.col3
 18      );
USING source_table src
      *
ERROR at line 2:
ORA-30926: unable to get a stable set of rows in the source tables


SQL>
因此,正如预期的那样,我们得到了错误ORA-30926:无法在源表中获得一组稳定的行

让我们将上的
子句设置为唯一的

SQL> MERGE INTO target_table trg
  2  USING source_table src
  3  ON (trg.col1 = src.col1
  4  AND
  5      trg.col2 = src.col2) -- Unique
  6  WHEN MATCHED THEN UPDATE SET
  7      trg.col3 = src.col3
  8  WHEN NOT MATCHED THEN INSERT
  9      (
 10          col1,
 11          col2,
 12          col3
 13      )
 14      VALUES
 15      (
 16          src.col1,
 17          src.col2,
 18          src.col3
 19      );

4 rows merged.

SQL> SELECT * FROM target_table;

      COL1 COL2       COL3
---------- ---------- ----------
         1 b          q
         3 d          q
         2 c          r
         3 c          s
         1 a          p

SQL>
问题解决了


请记住,您无法更新ON子句中引用的列。假设我们有这个表T2:

C1 C2     AMOUNT         UF
-- -- ---------- ----------
A  X          12        101
A  Y           3        102
A  Y          12        103
B  X           7        104
B  Y           9        105
我需要将表1中的记录与中的join字段匹配 他们的记录组的每个MAX()记录都已更新。我从 Fri.沿着路径沿着分区往下走,我对那个分区还不熟悉,所以没有做任何修改 进展很大

这是一条很好的路径,您可以使用函数:

但如果
merge
的加入字段仅为“C1”,则这组记录不稳定,因为对于C1='A' 我们有两排,甲骨文看起来很不好意思,它不知道你对哪一排感兴趣。 要解决此问题,您可以使用 而不是rank()-如果它都一样。但是如果这很重要,您需要在
order
子句中添加更多内容,例如:

select * from ( 
    select t2.*, rank() over (partition by c1 order by amount desc, c2) rn from t2 )
  where rn = 1

C1 C2     AMOUNT         UF  RN
-- -- ---------- ----------  --
A  X          12        101   1
B  Y           9        105   1
这组行是稳定的,因为对于C1,没有重复的行,您可以在
合并中使用它

merge into t1
using (
  select * from ( 
      select t2.*, rank() over (partition by c1 order by amount desc, c2) rn from t2 )
    where rn=1) md
on (md.c1 = t1.c1)
when matched then update set t1.uf = md.uf
when not matched then insert (t1.c1, t1.uf)
  values (md.c1, md.uf)

谢谢,Lalit,我进去后第一件事就是试试(大约6小时后)并用结果更新此页面。当然,请将其标记为回答,这将帮助其他人。谢谢Lalit。我得出结论,对于我需要做的事情,这是错误的方法。因此,我屏住呼吸,想出了一个应对挑战的新策略,并将我需要做的更新减少到2个普通DML a操作:插入相关子查询,然后进行基于自连接的更新。就我的问题的上下文而言,这样做了。但衷心感谢您花时间回复,我相信这不会浪费时间。感谢您的反馈。您好,Pounder,请查看我对Lalit的回复,感谢您的帮助!
merge into t1
using (
  select * from ( 
      select t2.*, rank() over (partition by c1 order by amount desc, c2) rn from t2 )
    where rn=1) md
on (md.c1 = t1.c1)
when matched then update set t1.uf = md.uf
when not matched then insert (t1.c1, t1.uf)
  values (md.c1, md.uf)