【问题标题】:Oracle SQL, merge into: add condition only where there are multiple matchesOracle SQL,合并到:仅在有多个匹配项的情况下添加条件
【发布时间】:2019-09-19 10:18:47
【问题描述】:

我的merge into 无法运行,因为“开启”条件无法识别表之间的一一对应关系。我想通过询问仅在条件失败的行来解决这个问题,使用第三列的值来决定。

merge into A using B
on (A.id = B.id and A.date between B.startdate and B.enddate)
when matched then update set 
A.foo = B.foo
-- where B.tiecondition = 1 * 

* 这不好,因为它总是运行,而我只想在主要“合并”条件有多个匹配项时使用该条件。发生这种情况是因为,对于某些 B.id 行,随后的 [B.startdate, B.enddate] 间隔实际上是重叠的(即,对于给定的 A.date,可能有多个 B.foo 值)。在这些情况下,B.tiecondition 列将允许我在可能的匹配项中做出选择。

我想'on'子句可能会被修改为类似

on (
    (A.id = B.id and A.date between B.startdate and B.enddate) 
or  (A.id = B.id and (A.date between B.startdate and B.enddate) and B.tiecondition = 1)
)  

但我不确定我是否会得到正确的结果,或者是否有更优雅的方法来做到这一点。

也许我可以改用left join,并添加几个条件检查结果中是否有多个匹配项,并只保留满足条件的行,但这看起来也有点麻烦。

【问题讨论】:

  • A.date is between B.startdate and B.enddate 在语法上无效。您需要删除 is 关键字。
  • @Giuseppe 。 . .如果这就是merge 中的全部内容,update 可能会更简单。
  • 对,对不起。我更正了。

标签: sql oracle join sql-merge


【解决方案1】:

如果我的要求正确,那么您需要 COUNT 将发生多少匹配,如果只有一个匹配,则接受它(无论 tie_condition 值如何)否则选择匹配tie_condition = 1

Oracle 设置

CREATE TABLE A ( id, dt, foo ) AS
SELECT 1, DATE '2019-09-19', CAST( NULL AS VARCHAR2(5) ) FROM DUAL UNION ALL
SELECT 2, DATE '2019-09-19', CAST( NULL AS VARCHAR2(5) ) FROM DUAL;

CREATE TABLE B ( id, startdate, enddate, tie_condition, foo ) AS
SELECT 1, DATE '2019-09-01', DATE '2019-09-30', 1, 'A' FROM DUAL UNION ALL
SELECT 1, DATE '2019-09-10', DATE '2019-09-20', 0, 'B' FROM DUAL UNION ALL
SELECT 1, DATE '2019-09-19', DATE '2019-09-29', 0, 'C' FROM DUAL UNION ALL
SELECT 2, DATE '2019-09-18', DATE '2019-09-20', 0, 'D' FROM DUAL;

合并

merge into A
using ( SELECT A.ROWID As rid,
               COUNT(*) OVER ( PARTITION BY A.ROWID ) AS num_matches,
               b.tie_condition,
               b.foo
        FROM   A
               INNER JOIN B
               ON (A.id = B.id and A.dt between B.startdate and B.enddate )
) B
on (A.ROWID = B.rid AND ( B.num_matches = 1 OR B.tie_condition = 1 ) )
when matched then
  update set A.foo = B.foo

结果

SELECT * FROM A

输出:

身份证 | DT |食品 -: | :-------- | :-- 1 | 19-SEP-19 |一种 2 | 19-SEP-19 | D

db小提琴here

【讨论】:

  • db<>fiddle 您也可以使用ROW_NUMBER(而不是COUNT)它使您如何执行连接变得不太清楚(因此当代码是不太容易理解),但如果您遇到表 B 可以在 tie_condition = 1 处有两个匹配行的情况,它不会失败(希望您无法到达,否则 tie_condition 列似乎毫无意义)。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-29
  • 1970-01-01
  • 2021-11-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-30
相关资源
最近更新 更多