Oracle SQL, объединить в: добавить условие только при наличии нескольких совпадений - PullRequest
0 голосов
/ 19 сентября 2019

My 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 * 

* это не хорошопотому что он работает всегда, в то время как я хочу использовать условие только тогда, когда есть несколько совпадений для основного условия «слияния».Это происходит потому, что для некоторых строк B.id последующие интервалы [B.startdate, B.enddate] фактически перекрываются (т. Е. Для данной даты A. возможно более одного значения 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 и добавить пару условий, проверяющих, когда несколькосовпадения в результатах и ​​сохранение только тех строк, которые удовлетворяют условию, но это тоже выглядит немного громоздко.

1 Ответ

3 голосов
/ 19 сентября 2019

Если я правильно выполнил ваши требования, вам нужно 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  

дБ <> скрипка здесь

...