2012-02-23 5 views
1

я следующие таблицы:SQL Server EXISTS запрос для определения отношения

Foo

FooId INT PRIMARY KEY 

FooRelationship

FooRelationshipId INT PRIMARY KEY IDENTITY 
    FooParentId INT FK 
    FooChildId INT FK 

Как бы написать запрос, который будет возвращать каждый id из Foo и статус записи (будь то родитель, ребенок или нет).

Правила:

  • Foo будет только один из родителей или ребенка, или ни.
  • Foo может быть родителем нескольких разных foos.
  • Foo не может быть ребенком более одного foo.

Я первоначально написал этот вопрос:

SELECT 
    FooId, 
    CASE 
     WHEN Parent.FooRelationshipId IS NOT NULL THEN 'Parent' 
     WHEN Child.FooRelationshipId IS NOT NULL THEN 'Child' 
     ELSE 'Neither' 
    END 
FROM Foo F 
LEFT JOIN FooRelationship Parent ON F.FooId = Parent.FooParentId 
LEFT JOIN FooRelationship Child ON F.Fooid = Child.FooParentId 

Это нарушается, потому что если Foo является родителем два других Фооса то возвращает этот идентификатор дважды.

Как я могу переписать это, чтобы либо не использовать соединение, либо использовать EXISTS или что-то еще.

ответ

2

Просто используйте DISTINCT - это хороший прецедент для этого. Вы не можете использовать EXISTS, так как вы на самом деле нужно вытащить данные из обеих таблиц:

SELECT DISTINCT 
    FooId, 
    CASE 
     WHEN Parent.FooRelationshipId IS NOT NULL THEN 'Parent' 
     WHEN Child.FooRelationshipId IS NOT NULL THEN 'Child' 
     ELSE 'Neither' 
    END 
FROM Foo F 
LEFT JOIN FooRelationship Parent ON F.FooId = Parent.FooParentId 
LEFT JOIN FooRelationship Child ON F.Fooid = Child.FooParentId 

Я обычно не большой поклонник DISTINCT, потому что он часто используется, чтобы скрыть грязные данные, но я думаю, что это соответствующее использование для этого.

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

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

SELECT s.FooID, s.Relationship, T.* 
FROM Table T 
INNER JOIN (SELECT DISTINCT 
    FooId, 
    CASE 
     WHEN Parent.FooRelationshipId IS NOT NULL THEN 'Parent' 
     WHEN Child.FooRelationshipId IS NOT NULL THEN 'Child' 
     ELSE 'Neither' 
    END as [Relationship] 
    FROM Foo F 
    LEFT JOIN FooRelationship Parent ON F.FooId = Parent.FooParentId 
    LEFT JOIN FooRelationship Child ON F.Fooid = Child.FooParentId) s 
ON s.FooId = t.FooID 
+0

Есть ли лучший способ написать этот запрос. Меня волнует производительность, потому что в этой таблице довольно много строк, и у них около 30-40 столбцов? – Dismissile

+0

@ Dismissile Мне нужна дополнительная информация, но одним из вариантов будет использование вашего примерного (узкого) запроса в качестве подзапроса и JOIN. Затем вы можете получить информацию «FooID, Relationship», не получая остальную часть строк, и «JOIN». Я отправлю пример. – JNK

+0

Спасибо, это очень помогло. – Dismissile

0

Попробуйте использовать SELECT DISTINCT FooID, ...

это будет возврат только один FooID в случае, если вы упомянули как проблемный

+0

Он фактически вернет только одну строку за уникальную комбинацию значений строк, а не только' FooID' – JNK

0

Просто измените существующий запрос, чтобы сделать select distinct вместо простой select.

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