2010-03-28 4 views
19

Мой вопрос очень похож на Restricting a LEFT JOIN с вариацией.Удалить дубликаты от LEFT OUTER JOIN

Предполагая, что у меня есть стол SHOP и другая таблица LOCATION. Местоположение - это своего рода дочерняя таблица таблицы SHOP, которая имеет два столбца, представляющих интерес, один - это ключ раздела (называющий его KEY) и номер «SHOP». Это соответствует номеру «НЕТ» в таблице SHOP.

Я попробовал эту левые внешнее соединение:

SELECT S.NO, L.KEY 
FROM SHOP S 
LEFT OUTER JOIN LOCATN L ON S.NO = L.SHOP 

, но я получаю много дублей, так как есть много мест, которые принадлежат к одному магазину. Я хочу их устранить и просто получить список записей «магазин, ключ» без дубликатов.

данные верны, но дубликаты выглядят следующим образом:

SHOP  KEY 
1  XXX 
1  XXX 
2  YYY 
3  ZZZ 
3  ZZZ etc. 

Я хотел бы данные, чтобы выглядеть как это вместо:

SHOP  KEY 
1  XXX 
2  YYY 
3  ZZZ etc. 

МАГАЗИН стол:

NO 
1  
2  
3  

МЕСТОНАХОЖДЕНИЕ стол:

LOCATION SHOP KEY 
    L-1  1 XXX 
    L-2  1 XXX 
    L-3  2 YYY 
    L-4  3 YYY 
    L-5  3 YYY 

(ORACLE Database 10g)

+0

Вы не должны получать какие-либо дубликаты, хотя, как вы заявили, вы можете получить более одного ключа для магазина, если у вас есть несколько записей местоположения для магазина. Пожалуйста, объясните или укажите пример того, что вы подразумеваете под «дублированием». –

+1

@Marcus Я думал, что сначала, но я предполагаю, что несколько местоположений могут иметь один и тот же ключ разделения. –

+0

@Marcus & Martin: ах, я не думаю, что я это ясно понял. Да Несколько мест могут иметь и иметь один и тот же ключ разделения. (Строго говоря, divnkey является родителем магазина. Таким образом, иерархия похожа на это Divnkey> Shop> location). Я пытаюсь заполнить таблицу Shop соответствующими данными ключа разделения. Может показаться странным, но это одноразовый процесс, и я пытался генерировать сценарии обновления для таблицы SHOP из таблицы данных LOCATION - с помощью команды select update set set divnkey = ..... Не хотел усложнять вопрос, поэтому поставил простой выбор. –

ответ

24

Вы должны GROUP BY «» S.No & «L.KEY»

SELECT S.NO, L.KEY 
FROM SHOP S 
LEFT OUTER JOIN LOCATN L 
ON S.NO = L.SHOP 
GROUP BY S.NO, L.KEY 
+0

+1 для использования 'GROUP BY', который эквивалентен' DISTINCT' на Oracle http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:32961403234212, но иногда могут быть быстрее на других двигателях, например Postgres (используя хеши вместо сортировки.) – vladr

+0

Ок, вы просто заставляли меня чувствовать себя глупо. Это прекрасно работает. Благодарю. Но любые дополнительные комментарии о том, почему группа требуется вообще, когда левый внешний должен позаботиться об этом. Как и в том, что я пытаюсь понять, как работает левый внешний. –

+0

@ Kaushik: LEFT OUTER JOIN не эквивалентен и не подразумевает GROUP BY или DISTINCT. LEFT JOIN берет все строки из левой (первой) таблицы и объединяется во все строки из правой (второй) таблицы, где выполняется условие соединения. В левом * внешнем * соединении, если в правой таблице нет данных, которые соответствуют данным из левой таблицы, данные левой таблицы все еще возвращаются с NULL, помещенными для всех данных правой таблицы. Никакая группировка не выражается или подразумевается. Лично я бы использовал DISTINCT, поскольку я думаю, что это более четко указывает намерение, но YMMV. –

7

EDIT После обновления в вашем сценарии

Я думаю, вы должны быть в состоянии сделать это с помощью простого запроса к югу (хотя я не проверял это против База данных Oracle). Что-то вроде следующего

UPDATE shop s 
SET divnkey = (SELECT DISTINCT L.KEY FROM LOCATN L WHERE S.NO = L.SHOP) 

выше вызовет ошибку в случае магазина, ассоциированный с местами, которые находятся в нескольких подразделениях.

Если вы просто хотите, чтобы игнорировать эту возможность и выбрать произвольный один в этом случае вы могли бы использовать

UPDATE shop s 
SET divnkey = (SELECT MAX(L.KEY) FROM LOCATN L WHERE S.NO = L.SHOP) 
+0

Nice :) Вот почему важно получить более одного угла. Спасибо Мартину, ваше решение наиболее точно удовлетворяет моему основному требованию (но другой ответ, в частности, позаботится об удалении дубликатов, поэтому придется отметить это). Cheers –

6

У меня тоже была эта проблема, но я не мог использовать GROUP BY, чтобы исправить ее, потому что я также возвращал поля типа TEXT. (То же самое касается использования DISTINCT).

Этот код дал мне дублирует:

select mx.*, case isnull(ty.ty_id,0) when 0 then 'N' else 'Y' end as inuse 
from master_x mx 
left outer join thing_y ty on mx.rpt_id = ty.rpt_id 

Я установил его, переписав его таким образом:

select mx.*, 
case when exists (select 1 from thing_y ty where mx.rpt_id = ty.rpt_id) then 'Y' else 'N' end as inuse 
from master_x mx 

Как вы можете видеть, что я не забочусь о данных в рамках 2-й таблицы (thing_y), просто ли было больше нуля совпадений на rpt_id внутри него. (FYI: rpt_id также не был первичным ключом в 1-м столе, master_x).