2017-02-14 7 views
2

Сегодня у меня возникла проблема у друга.Удалить дубликаты, используя только там, где условие

Проблема - Напишите SQL-запрос, используя UNION ALL (не объединение), в котором используется предложение where для устранения дубликатов.

  • Я не могу использовать группу выражением
  • Я не могу использовать уникальные, различные ключевые слова.

Вход -

id(Table 1) 
1 
2 

fk_id(Table 2) 
1 
1 
2 

Я дал ему решение под запрос

select id from 
(
select id , row_number() over(partition by id order by id) rn from 
(
select id from T1 
union all 
select fk_ID id from T2 
) 
)where rn = 1; 

Output - 
id 
1 
2 

который производящего уникальные идентификаторы.

Теперь его неизвестно, я также не могу использовать row_number(). я просто должен использовать, где условие. Я пишу запрос в базе данных оракула.

Просьба предложить.

Заранее спасибо.

+0

Интересные академический вопрос, возможно, практически без практического применения. –

+0

Почему мы не можем использовать row_number()? – BobC

+0

@BobC в соответствии с вопросом, я должен использовать только предложение where, чтобы получить желаемые результаты. Пожалуйста, предложите. – Tajinder

ответ

4

От его имени и данных, которые можно считать, id в таблице t1 уникален.

От своего имени и приведенных данных можно предположить, что fk_id в таблице t2 является иностранным ключом к table1.id.

Таким образом, объединение идентификаторов в двух таблицах - это просто идентификаторы, которые мы находим в таблице t1.

Как мы вынуждены использовать UNION ALL на двух столах, однако, мы можем использовать псевдо-UNION ALL ничего не добавляя:

select id from t1 
union all 
select fk_id from t2 where 1 = 2; 

Если t2.fk_id не было внешнего ключа ссылки t1.id, мы будем использовать NOT EXISTS или NOT IN в предложении where. Однако, если это означает, что результат не будет дублироваться, то в t2 не должно быть дубликатов, чтобы начать с. (Как вы показываете, что повторяющиеся значения в t2 существуют, такой подход не будет работать тогда.) Вот запрос уникальных значений из t1 плюс уникальных значений из t2, не ссылаясь на t1 значения:

select id from t1 
union all 
select fk_id from t2 where fk_id not in (select id from t1); 
+0

Большое вам спасибо, человек замечательный. – Tajinder

+0

Не могли бы вы написать запрос, если между таблицей нет отношения первичного внешнего ключа? – Tajinder

+0

этот запрос будет работать и в вашем случае. если они не являются основным и внешним ключом –

2

В более общем случае, где у вас могут быть дубликаты в обеих таблицах, это может быть способ.

тестовых данных:

create table table1(id) as ( 
    select 1 from dual union all 
    select 1 from dual union all 
    select 2 from dual union all 
    select 2 from dual union all 
    select 1 from dual 
) 

create table table2(fk_id) as (
    select 1 from dual union all 
    select 1 from dual union all 
    select 1 from dual union all 
    select 3 from dual union all 
    select 4 from dual union all 
    select 1 from dual union all 
    select 4 from dual union all 
    select 2 from dual 
) 

запроса:

with tab1_union_all_tab2 as ( 
    select 'tab1'||rownum as uniqueId, id from table1 UNION ALL 
    select 'tab2'||rownum   , fk_id from table2 
)  
select id 
from tab1_union_all_tab2 u1 
where not exists (select 1 
        from tab1_union_all_tab2 u2 
        where u1.id = u2.id 
        and u1.uniqueId < u2.uniqueId 
       ) 

Результат:

ID 
---------- 
     3 
     4 
     1 
     2 

Это должно прояснить I DEA позади:

with tab1_union_all_tab2 as ( 
    select 'tab1'||rownum as uniqueId, id from table1 UNION ALL 
    select 'tab2'||rownum   , fk_id from table2 
)  
select uniqueId, id, 
     (select nvl(listagg (uniqueId, ', ') within group (order by uniqueId), 'NO DUPLICATES') 
      from tab1_union_all_tab2 u2 
     where u1.id = u2.id 
      and u1.uniqueId < u2.uniqueId 
     ) duplicates 
from tab1_union_all_tab2 u1 

UNIQUEID   ID DUPLICATES 
---------- ---------- -------------------------------------------------- 
tab11    1 tab12, tab15, tab21, tab22, tab23, tab26 
tab12    1 tab15, tab21, tab22, tab23, tab26 
tab13    2 tab14, tab28 
tab14    2 tab28 
tab15    1 tab21, tab22, tab23, tab26 
tab21    1 tab22, tab23, tab26 
tab22    1 tab23, tab26 
tab23    1 tab26 
tab24    3 NO DUPLICATES 
tab25    4 tab27 
tab26    1 NO DUPLICATES 
tab27    4 NO DUPLICATES 
tab28    2 NO DUPLICATES 

Как справедливо заметил Торстен Kettner, вы можете легко изменить это использовать rowid вместо создания уникального идентификатора путем конкатенации строки и rownum:

with tab1_union_all_tab2 as ( 
    select rowid uniqueId, id from table1 UNION ALL 
    select rowid   , fk_id from table2 
)  
select id 
from tab1_union_all_tab2 u1 
where not exists (select 1 
        from tab1_union_all_tab2 u2 
        where u1.id = u2.id 
        and u1.uniqueId < u2.uniqueId 
       ) 
+0

Для Oracle это отличное решение, работающее даже с возможными дублирующими значениями в обеих таблицах. (То же самое можно сделать, просто используя Oracle ROWID, кстати, так что вам не нужно создавать уникальный идентификатор строки самостоятельно.) Ответ был бы еще лучше с кратким объяснением, что делает запрос и почему вы решили использовать этот подход. +1 от меня. –

+0

@Aleksej Спасибо за ваше усилие – Tajinder

1

записи а, где оператор для второго выбора в объединении все как где id! = fk_id

Смежные вопросы