2009-08-10 170 views
2

我有两个表:授权和结算。 '定居点'包含对授权的外键引用。筛选LEFT JOIN结果

结算也可以有一个状态(错误,接受等)。

鉴于这样的数据:

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

我想写一个SQL查询来发现,没有一个公认的结算记录所有授权。我尝试了一个左外连接,但它返回太多行。例如:

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,还是必须在我的代码中过滤结果?

回答

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打我的头发 – 2009-08-10 17:30:35

+0

谢谢!这工作完美。 – MikeQ 2009-08-10 18:39:16

0

根据你的榜样,检查的s.status被空,如果你改变连接是右连接是不必要的。

将与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

如果'settlements'中没有相应的记录,那么您的解决方案都不会返回'授权'。在'@ op'的例子中,授权'2'不会被返回。 – Quassnoi 2009-08-10 17:56:48

+0

根据OP:“我怎样才能取得没有相应结算记录且状态为”ACCEPTED“的单一授权记录?”没有要求说明需要没有任何SETTLEMENT记录的AUTHORIZATION记录。 – 2009-08-10 18:09:01

+0

授权'2'没有状态为“ACCEPTED”的相应结算记录。这是原始查询中“LEFT JOIN”的全部内容。 – Quassnoi 2009-08-10 18:21:20

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 

此挑选出所有被接受的记录然后采取不属于该组的授权。