我有两张桌子:授权和和解。 “结算”包含授权的外键引用。
和解也可以具有状态(错误,接受等)。
鉴于此数据:
Authorizations Settlements id id | auth_id | status ----- --------------------------- 1 1 1 ERROR 2 2 1 ACCEPTED
我正在尝试编写SQL查询以查找没有ACCEPTED结算记录的所有授权。我尝试过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记录,则授权将返回两次。
如何才能获取单个授权记录,这些记录没有状态为“ACCEPTED”的相应结算记录?是否可以使用直接SQL,或者我是否必须在代码中过滤结果?
答案 0 :(得分:7)
SELECT *
FROM authorizations a
WHERE NOT EXISTS
(
SELECT NULL
FROM Settlements s
WHERE s.auth_id = a.id
AND s.status = 'ACCEPTED'
)
答案 1 :(得分: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
这将挑选出所有被接受的记录,然后获取不属于该组的授权。
答案 2 :(得分:0)
根据您的示例,如果您将JOIN更改为RIGHT联接,则不需要检查s.status为null。
适用于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