Oracle SQL, merge into: add condition only where there multiple matches

Oracle SQL, merge into: add condition only where there are multiple matches

我的 merge into 不能 运行 因为 'on' 条件不识别表之间的一对一对应关系。我想通过询问仅在条件失败的行来解决这个问题,第三列的值用于决定。

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 * 

* 这不好,因为它总是运行,而我只想在主 "merge on" 条件有多个匹配项时才使用该条件。发生这种情况是因为,对于某些 B.id 行,后续 [B.startdate、B.enddate] 间隔实际上重叠(即对于给定的 [=34= 可能有多个 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,并添加几个条件来检查结果中是否存在多个匹配项,并只保留满足条件的行,但这看起来也有点麻烦。

如果我的要求正确,那么您需要 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

输出:

ID | DT        | FOO
-: | :-------- | :--
 1 | 19-SEP-19 | A  
 2 | 19-SEP-19 | D  

db<>fiddle here