在不使用SQL中的子查询的情况下筛选客户



如果不使用子查询,我如何找到在过去6个月内没有购买任何书籍的客户。

SELECT first_name, last_name, email
FROM customers
WHERE id NOT IN (
SELECT customers.id
FROM customers
LEFT JOIN orders ON orders.customer_id = customers.id
WHERE DATEDIFF(MONTH, orders.purchased_date, GETDATE()) < 6
GROUP BY customers.id
);

这里有一个没有子查询的选项(不清楚为什么(。。。只是蛮力:(

Select C.first_name
,C.last_name
,C.email
,LastPurchase = max(O.purchased_date)
From customers C
Join orders    O on O.customer_id = C.customer_id 
Group by C.customer_id
,C.first_name
,C.last_name
,C.email
Having max(O.purchased_date) <= dateadd(month,-6,getdate())

为什么不使用子查询?这是这里工作的最佳工具。您可以使用NOT EXISTS而不是IN来改进查询(同时仍然使用子查询(,并且不将DATEDIFF函数直接应用于列,因为这会使查询不可排序(即不能使用索引(。此外,DATEDIFF统计从那时到现在的月份变化,而不是实际月份。请参阅下面的逻辑更改。

SELECT c.first_name, c.last_name, c.email
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customer_id = c.customers.id
AND o.purchased_date >= DATEADD(MONTH, -6, GETDATE())
)

也总是建议使用表别名。

假设您从性能的角度提出了这个问题,我使用估计的执行计划,对照我拥有的499290个客户和1333326个订单的真实表,大致检查了它的性能。您的查询占43%,John的查询占39%(略有改进(,我的查询占9%(大幅改进(,SMor的查询占90%(再次大幅改进(。因此,如果性能真的是你的问题所在,你应该问这个问题,而不是人为地限制性能最好的解决方案。

EXCEPT作为一种kludge-y替代方案出现在脑海中。cte获取所有客户ID,然后根据购买日期在6个月内的订单删除这些ID。然后,您只需将cte加入到客户表中即可。

with cte as (
select customer_id from dbo.customers
except
select customer_id from dbo.orders where purchase_date >= dateadd(month, -6, getdate())
)
select cust.customer_id, ... 
from dbo.customers as cust
inner join cte on cte.customer_id = cust.customer_id
order by ...;

最新更新