2010-09-10 71 views
3

我有一个表连接的客户以前购买:如何找到购买了一种产品而非另一种产品的人?

RecID CustID ProdID 
    1  20  105 
    2  20  300 
    3  31  105 
    4  45  105 
    5  45  300 
    6  45  312 

我想获得那买项目105 但不是没有,但项目300

在这种情况下CustIDs的列表, CustID 31.

我似乎无法做到与选择和连接。我很难过!

我当然希望得到一些有经验的SQL人员的帮助。

谢谢!


谢谢!

我是问题的原始作者。

马克·比尔斯与NOT IN的第二个例子很好用! (在这个为我工作之后,我没有尝试别人)。

他的第一个LEFT JOIN示例没有返回任何CustIDs ...我认为我正确地复制了它并使用了正确的表名和列名。所以我不知道为什么它不适合我。

再次感谢所有善于花时间为我写出一些SQL的人。

我不得不创建一个新帐户来发表评论(我不能,我这个昨天创建的帐户登录,密码恢复表示无法找到我)

+0

数据库和版本? – 2010-09-10 22:38:41

+0

从用户的问题历史来看,我猜测他们对* SQL Server *感兴趣。 – 2010-09-10 23:02:40

回答

5

常见的有三种方法。这里是一个LEFT JOIN方法:

SELECT T1.CustID 
FROM yourtable T1 
LEFT JOIN yourtable T2 ON T1.CustID = T2.CustID AND T2.ProdId = 300 
WHERE T1.ProdId = 105 
AND T2.ProdId IS NULL 

这里就不:

SELECT CustID 
FROM yourtable 
WHERE ProdId = 105 
AND CustID NOT IN 
(
    SELECT CustID 
    FROM yourtable 
    WHERE ProdId = 300 
) 

或者你可以使用NOT EXISTS:

SELECT CustID 
FROM yourtable T1 
WHERE ProdId = 105 
AND NOT EXISTS 
(
    SELECT NULL 
    FROM yourtable T2 
    WHERE T2.ProdId = 300 
    AND T2.CustID = T1.CustID 
) 

其中有更好的性能取决于它的数据库和版本上您正在使用。


对于SQL Server最好是为使用NOT IN或NOT EXISTS:

在SQL Server中,NOT EXISTS和NOT IN谓词是寻找失踪值的最佳方式,只要因为所讨论的两列都不是NULL。他们用某种反加入来生成安全高效的计划。

LEFT JOIN/IS NULL效率较低,因为它不会尝试跳过右表中已匹配的值,返回所有结果并将其过滤掉。

来源:

+0

您可能想指出第二个版本在大数据集上的速度可能非常慢,与其他版本相比 – DVK 2010-09-10 22:37:54

+0

@DVK:这并非总是如此。这取决于数据库。 * LEFT JOIN/IS NULL和NOT IN最适合用于在MySQL中实现反连接,如果两边的列都不能为空。*来源:http://explainextended.com/2010/05/27/left-join -is-null-vs-not-in-vs-not-exists-nullable-columns/ – 2010-09-10 22:40:14

+0

是的,在Sybase和IIRC Oracle中确实如此。没有MySQL经验,但链接的解释听起来似乎合理。 – DVK 2010-09-10 22:44:39

3
SELECT CustID from T T1 
WHERE ProdID = 105 
    AND NOT EXISTS (SELECT 1 from T T2 
        WHERE T2.ProdID = 300 
        AND T2.CustID = T1.CustID) 
+0

+1对于NOT EXISTS – 2010-09-10 22:36:16

+1

+1 - 打我几秒 – LittleBobbyTables 2010-09-10 22:50:09

+2

我想我当我的SQL被名为BobbyTables的人称赞时,应该开始担心了:) – DVK 2010-09-10 22:58:09

1

几个不同的方法。

select CustID from t where ProdID=105 
except 
select CustID from t where ProdID=300 

select CustID 
from t 
where ProdID in (105,300) 
group by CustID 
having max(ProdID)=105 
0
SELECT PPT.CustID FROM PreviousPurchasesTable PPT 
WHERE PPT.ProdID = 105 
AND PPT.CustID NOT IN (SELECT PPT2.CustID FROM PreviousPurchasesTable PPT2 WHERE PPT2.ProdID = 300) 
相关问题