代码之家  ›  专栏  ›  技术社区  ›  George Menoutis

存在(A)和不存在(negA)与自定义聚合

  •  0
  • George Menoutis  · 技术社区  · 6 年前

    很多时候,我必须选择已经进行了{criteriaseta}事务的客户,而不是任何其他类型的事务。样本数据:

    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')
    

    最典型的方法包括将事务表与自身连接起来:

    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
    )
    

    事务表只使用一次这一事实会抵消所需的聚合计算吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Yogesh Sharma    6 年前

    您需要在上测试性能 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 子句对于处理所有不同的“集合内集合”条件非常灵活。
    • 添加附加条件对性能影响不大。
    • 如果您不使用customer表,而是执行以下操作 (select distinct customer from trn) ,然后 存在 不存在

        2
  •  0
  •   Marc_Sei    6 年前

    你可以试试下面的说法。它 在某些情况下比您的声明要快,因为它总是首先确定有产品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')