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
我的 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