Фильтрация результатов LEFT JOIN - PullRequest
2 голосов
/ 10 августа 2009

У меня есть две таблицы: полномочия и расчеты. «Расчеты» содержат стороннюю ссылку на полномочия.

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

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

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

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

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

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

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

Ответы [ 3 ]

7 голосов
/ 10 августа 2009
SELECT  *
FROM    authorizations a
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    Settlements s
        WHERE   s.auth_id = a.id
                AND s.status = 'ACCEPTED'
        )
2 голосов
/ 10 августа 2009

Попробуйте

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

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

0 голосов
/ 10 августа 2009

Исходя из вашего примера, проверка того, что s.status имеет значение null, не требуется, если вы меняете 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  
...