#sql #oracle #oracle-sqldeveloper
#sql #Oracle #oracle-sqldeveloper
Вопрос:
У меня есть две таблицы per_asg
и xx_asg
, они имеют одинаковое количество столбцов и в идеале должны иметь одинаковый номер. данных.
per_asg:
person_id start_date end_date
-------------------------------------------
1 01-jan-2016 07-jan-2016
1 02-feb-2016 08-march-2016
xx_per_asg
person_id start_date end_date
-------------------------------------
1 01-jan-2016 07-jan-2016
1 02-feb-2016 08-march-2016
1 03-feb-2016 04-sep-2016
Как видно на xx_per_asg, есть одна дополнительная строка с start_date '03-feb-2016'
и end_date '04-sep-2016'.
Я написал запрос для извлечения таких строк, но я не получаю дополнительные строки полностью :
select start_date
from xx_per_asg xx_per_asg, per_asg pa
where xx_per_asg.person_id = pa.person_id
and xx_per_asg.start_date <> pa.start_date
Но это все равно приведет ко всему набору данных
Комментарии:
1. Вредные привычки, от которых следует отказаться: использование объединений в старом стиле — этот старый стиль списка таблиц, разделенных запятыми , был заменен на надлежащий синтаксис ANSI
JOIN
в стандарте ANSI- 92 SQL ( более 20 лет назад), и его использование не рекомендуется
Ответ №1:
Если вам нужны дополнительные строки, я бы ожидал запрос, более похожий на этот:
select xx.*
from xx_per_asg xx
where not exists (select 1
from per_asg pa
where pa.person_id = xx.person_id and
pa.start_date = xx.start_date
);
Ответ №2:
Если в каждой таблице могут быть строки, которых нет в другой таблице, и вам нужно найти оба вида, должно сработать что-то вроде этого. Предполагая, что ни в одной из таблиц нет повторяющихся строк (например, это было бы верно, если бы у каждой из них были первичные ключи), тогда, если вы создадите union all
из двух таблиц, строки, которые существуют в обеих таблицах, будут дубликатами при объединении. Те, которых нет в обеих таблицах, не будут дублироваться. Итак, после union all
мы можем сгруппировать по всем столбцам и использовать HAVING COUNT(*) = 1
условие, чтобы найти строки, которые есть только в одной таблице, но отсутствуют в другой.
Небольшая настройка этого также покажет нам, в какой таблице есть «непарная» строка для каждой строки. В решении я использую max(source)
(потому что мы не должны группировать по «источнику», поэтому нам нужно использовать для него агрегатную функцию), но на самом деле это max()
над одним значением; это будет просто это значение.
Это решение эффективно, потому что оно не использует объединения и не использует дорогостоящую MINUS
операцию (или, фактически, две MINUS
операции, а также чтение каждой таблицы дважды вместо одного раза, если заданием было найти непарные строки из обеих таблиц, а не только из одной).
select max(source), person_id, start_date, end_date
from ( select 'per_asg' as source, person_id, start_date, end_date from per_asg
union all
select 'xx_per_asg' as source, person_id, start_date, end_date from xx_per_asg
)
group by person_id, start_date, end_date
having count(*) = 1
order by person_id, start_date, end_date -- ORDER BY is optional
;
Еще одна вещь — если вы сравниваете по start_date
, вы должны быть уверены, что все даты являются «чистыми датами» (без компонента времени суток); то есть компонент времени должен быть 00:00:00
. Так ли это? Если это не так, все решения нужно будет скорректировать (и они станут менее эффективными, то есть отнимут больше времени).
Ответ №3:
Если, как видно из примера, строки в обеих таблицах равны, поле за полем, вы могли бы сделать:
select * from xx_per_asg
minus
select * from per_asg
Ответ №4:
Select xx.startdate,xx.enddate,xx.person_id from xx_per_asg xx
LEFT OUTER JOIN per_asg per on per.person_id = xx.person_id
Where xx.start_date <> per.start_date
Комментарии:
1. Я не уверен, что это сработает. Если у вас есть 2 строки с датами D1 и D2 в обеих таблицах t1 и t2, они будут отображаться в результирующем наборе как t1.D1<> t2.D2 и t2.D1<>t1.D2.