很多时候,我必须选择进行{criteria set A}交易而不是其他任何类型交易的客户。样本数据:
create table customer (name nvarchar(max))
insert customer values
('George'),
('Jack'),
('Leopold'),
('Averel')
create table trn (id int,customer nvarchar(max),product char(1))
insert trn values
(1,'George','A'),
(2,'George','B'),
(3,'Jack','B'),
(4,'Leopold','A')
比方说,我们要查找所有购买了商品“ A”的顾客,而不是其他顾客(在本例中为B)。 最典型的方法包括将事务表与其自身连接:
select * from customer c
where exists(select 1 from trn p where p.customer=c.name and product='A')
and not exists(select 1 from trn n where n.customer=c.name and product='B')
我想知道是否有更好的方法可以做到这一点。请记住,交易表通常应该很大。
该替代方案如何?
select * from customer c
where exists
(
select 1
from trn p
where p.customer=c.name
group by p.customer
having max(case when product='B' then 2 when product='A' then 1 else 0 end)=1
)
交易表仅使用一次的事实会抵消所需的聚合计算吗?
答案 0 :(得分:1)
您需要测试您的数据的性能。如果您在trn(customer, product)
上有一个索引,那么exists
的性能通常会非常合理。
使用customers
表时尤其如此。
汇总版本的比较效果如何?首先,最好的汇总是:
select customer
from trn
where product in ('a', 'b')
group by customer
having min(product) = 'a' and max(product) = 'b';
如果您在product
上有一个索引-并且产品很多(或者很少有具有“ a”和“ b”的客户),那么这可能比not exists
版本更快
通常,我建议使用group by
,即使它在某些产品上的性能并不总是最佳。为什么?
having
子句非常灵活,可以处理所有不同的“组内设置”条件。(select distinct customer from trn)
的方式,则exists
/ not exists
版本可能会更昂贵。也就是说,我主张使用group by
和having
,因为它更灵活。这意味着在适当的情况下,应该使用其他解决方案。
答案 1 :(得分:0)
您可以尝试以下语句。在某些情况下,它可能比您的声明快,因为它始终会首先确定进行产品A交易的客户,然后在有其他产品的交易时才寻找这些客户。如果真的有好处,则取决于实际表的数据和索引,因此您必须尝试。
WITH customerA AS (SELECT DISTINCT customer FROM trn WHERE product = 'A')
SELECT DISTINCT customer.*
FROM customerA JOIN customer ON customerA.customer = customer.name
WHERE not exists(select 1 from trn n where n.customer = customerA.customer and
product <> 'A')