假设有一个包含此表的数据库:
订单
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');
谢谢!
答案 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­able <i>until</i>:</td><td>No expiry date</td><td>Avail­ability:</td><td>Worldwide</td><td></td>
</tr><tr>
<td>Year:</td><td>2016</td><td>Length:</td><td>29 minutes</td><td></td>
</tr><tr>
<td>First broad­cast:</td><td>Feb 2</td><td>Last broad­cast:</td><td>Feb 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'