2009-08-10 2 views
2

У меня есть две таблицы: разрешения и расчеты. В разделе «Расчеты» содержится ключевая ссылка на авторизацию.Фильтрация результатов ВЛЕВОГО СОЕДИНЕНИЯ

Урегулирование также может иметь статус (ОШИБКА, ПРИНЯТО и т. Д.).

Учитывая эти данные:

 
Authorizations   Settlements 
id    id | auth_id | status 
-----    --------------------------- 
1     1   1   ERROR 
2     2   1   ACCEPTED 

Я пытаюсь написать запрос SQL, чтобы найти все разрешения, которые не имеют обслуживаемую запись урегулирования. Я попробовал LEFT OUTER JOIN, но он возвращает слишком много строк. Например:

SELECT * FROM authorizations a
LEFT OUTER JOIN settlements s ON a.id = s.auth_id
WHERE s.status is null OR s.status != 'ACCEPTED'

Проблема с этим состоит в том, что он все равно будет возвращать запись авторизации, если она имеет более чем одну запись урегулирования, и один из них является ПРИНИМАЮТСЯ. Или, если имеется более одной записи ERROR, авторизация будет возвращена дважды.

Как я могу получить только одиночные записи авторизации, которые не имеют соответствующей записи о поселении со статусом «ПРИНЯТЫЕ»? Возможно ли это с помощью прямого SQL, или мне придется фильтровать результаты в моем коде?

ответ

7
SELECT * 
FROM authorizations a 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM Settlements s 
     WHERE s.auth_id = a.id 
       AND s.status = 'ACCEPTED' 
     ) 
+0

+1 избили меня этим волосом –

+0

Спасибо! Это сработало отлично. – MikeQ

0

На основании вашего примера проверка того, что s.status является нулевым, не является необходимым, если вы изменили JOIN как правое соединение.

будет работать с SQL Server 2005+ или Oracle 9i +:

WITH unacceptedSettlements AS (
    SELECT s.auth_id 
     FROM SETTLEMENTS s 
     WHERE s.status != 'ACCEPTED' 
    GROUP BY s.auth_id) 
SELECT t.* 
    FROM AUTHORIZATIONS t 
    JOIN unacceptedSettlements us ON us.auth_id = t.auth_id 

Любая база данных альтернатива:

SELECT t.* 
    FROM AUTHORIZATIONS t 
    JOIN (SELECT s.auth_id 
     FROM SETTLEMENTS s 
     WHERE s.status != 'ACCEPTED' 
     GROUP BY s.auth_id) us ON us.auth_id = t.auth_id 
+0

Оба ваших решения не вернут «авторизацию», если в «поселениях» нет соответствующей записи. В примере '@ op' авторизация' 2' не будет возвращена. – Quassnoi

+0

В OP: «Как я могу получить только отдельные записи авторизации, которые не имеют соответствующей записи расчета со статусом« ПРИНЯТЫЙ »?» Нет требования, заявленного для записи записей AUTHORIZATION без каких-либо записей SETTLEMENT. –

+0

Авторизация '2' не имеет соответствующей записи расчета со статусом' ACCEPTED'. В этом весь смысл «LEFT JOIN» в исходном запросе. – Quassnoi

2

Попробуйте

SELECT a.* FROM authorizations a 
LEFT OUTER JOIN (SELECT S.* from settlements s1 
WHERE s1.status = 'ACCEPTED') 
ON a.id = s.auth_id 
WHERE s.auth_id is null 

Это выбирает все записи, которые принимаются а затем принимает разрешения, которые не входят в эту группу.

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