订购' X'并且没有订购' Y' (MySQL的)

时间:2015-06-03 08:10:18

标签: mysql

假设有一个包含此表的数据库:

订单

OrderId  -  CustomerId
----------------------
100      -  1
101      -  2
102      -  1

Order_Details

DetailId  -  OrderId -  ProductId
---------------------------------
1         -  100     -  prod1
2         -  100     -  prod2
3         -  101     -  prod1
4         -  102     -  prod3

我需要获取购买产品&#39; 1&#39; 但尚未购买产品&#39; 2&#39; 的CustomerIds列表。< / p>

提供样本数据后,我应该获得CustomerId 2。

我写了这个SQL语句,但真正的数据库真的很大,运行速度很慢...... 有没有办法改善我的判刑?

SELECT DISTINCT(o.CustomerId) 
FROM orders o 
JOIN order_details od ON od.orderId = o.orderId
WHERE od.productId = 'prod1'
AND o.customerId NOT IN
  (SELECT DISTINCT(o.CustomerId) FROM order_details od2 WHERE
  od2.productId = 'prod2');

谢谢!

3 个答案:

答案 0 :(得分:2)

建议不要对大值列表使用IN运算符。 相反,您可以使用EXISTS或为查询添加更多联接。

使用存在:

SELECT DISTINCT(o.CustomerId) 
FROM orders o 
JOIN order_details od ON od.orderId = o.orderId
WHERE od.productId = 'prod1'
AND NOT EXISTS
(
    SELECT 1 
    FROM orders o2 
    JOIN order_details od2 ON od2.orderId = o2.orderId
    WHERE o2.customerId = o.customerId 
    AND od2.productId = 'prod2'
);

使用联接:

SELECT DISTINCT(o.CustomerId) 
FROM orders o 
INNER JOIN order_details od ON od.orderId = o.orderId
LEFT JOIN  order_details od2 ON od2.orderId = o.orderId AND od2.productId = 'prod1'
WHERE od.productId = 'prod1'
AND od2.DetailId IS NULL -- Assuming that the detailId column does not allow null values.

注意:代码是直接写在这里而未经过测试的,我可能犯了一些错误。为了获得更好的答案,我建议在查询中始终包含DDL + DML样本数据,这样人们就可以在发布之前检查答案。

答案 1 :(得分:2)

您可以将<table class="fluid-table"> <tr> <td>Avail&shy;able <i>until</i>:</td><td>No&nbsp;expiry date</td><td>Avail&shy;ability:</td><td>Worldwide</td><td></td> </tr><tr> <td>Year:</td><td>2016</td><td>Length:</td><td>29&nbsp;minutes</td><td></td> </tr><tr> <td>First broad&shy;cast:</td><td>Feb&nbsp;2</td><td>Last broad&shy;cast:</td><td>Feb&nbsp;3</td><td></td> </tr> </table> 转换为sub-query机制 https://dev.mysql.com/doc/refman/5.5/en/subquery-optimization-with-exists.html

exists

此外,您还需要为此编制索引。

假设SELECT DISTINCT o.CustomerId FROM orders o JOIN order_details od ON od.orderId = o.orderId WHERE od.productId = 'prod1' and not exists( select 1 from order_details od2 WHERE o.customerId = od2.customerId and od2.productId = 'prod2' ) orderId上的主要密钥,并且已在orders上编入索引,则需要

order_details

如果alter table order_details add index productId_idx(productId); 未在orderId上编入索引,请添加以下内容

order_details

答案 2 :(得分:2)

尝试使用减号

SELECT DISTINCT(o.CustomerId) 
FROM orders o 
JOIN order_details od ON od.orderId = o.orderId
WHERE od.productId = 'prod1'

MINUS

SELECT DISTINCT(o2.CustomerId) 
FROM orders o2 
JOIN order_details od2 ON od2.orderId = o2.orderId
WHERE o2.customerId = o.customerId 
AND od2.productId = 'prod2'