子集 a table 以包含仅与一组条目中的一次相关联的行

subset a table to include rows associated with only one occurence of a set of entries

我有以下 table 4 个人最喜欢的水果:

tbl:

ID         FRUIT
personA    banana
personB    apple
personC    orange
personD    grapefruit
personA    avocado
personB    banana
personC    melon
personD    pear
personA    banana

我想提取仅与以下一项关联的 ID 的所有条目:香蕉、苹果、橙子。

这意味着我只希望提取 A 人和 C 人的行。B 人同时拥有(“苹果”和“香蕉”)。人 D 有 none 个想要的三个水果。

我目前有:

select *
from tbl t1
where exists (select 1
              from tbl t2
              where t1.ID=t2.ID and
                    (t2.fruit='banana' or
                     t2.fruit='apple' or
                     t2.fruit='orange'))
join (select ID, count(*) over (partition by t3.fruit)
      from (select distinct ID, fruit
              from tbl
              where fruit='banana' or
                    fruit='apple' or
                    fruit='orange')) t3
on t3.ID=t.ID and
   t3.cnt=1

是否有 better/simpler 方法来执行此操作?我想优化它以减少 运行 时间,因为 table 非常大。

desired table:

ID         FRUIT
personA    banana
personC    orange
personA    avocado
personC    melon
personA    banana

我们可以使用 GROUP BY 和 HAVING COUNT(DISTINCT) 来找到我们想要的人。

SELECT 
  a.ID,
  b.FRUITID
FROM tb1 a
JOIN tb1 b ON a.ID = b.ID
WHERE a.FRUITID IN ('banana', 'apple', 'orange')
GROUP BY 
  a.ID,
  b.FRUITID
HAVING COUNT(DISTINCT a.FRUITID) = 1;
GO
ID      | FRUITID
:------ | :------
personA | avocado
personA | banana 
personC | melon  
personC | orange 

db<>fiddle here

子查询确定所有具有这三个水果的 ID,并计算它们有多少个水果。

你知道可以将 ID 加入到 table 并且只取那些只有 1 个水果的 ID,如果你也想要三个水果你并在加入条件中添加这个

SELECT 
    t1.ID, FRUIT
FROM
    tbl t1
        JOIN
    (SELECT 
        ID, COUNT(DISTINCT FRUIT) countf
    FROM
        tbl
    WHERE
        FRUIT IN ('banana', 'apple', 'orange')
    GROUP BY 1) t2 ON t1.ID = t2.ID AND t2.countf = 1;

另一种方法是使用 COUNT_IF:

SELECT *
FROM tbl t
QUALIFY COUNT_IF(t.fruit = 'banana') OVER(PARTITION BY ID) = 1
    AND COUNT_IF(t.fruit = 'apple')  OVER(PARTITION BY ID) = 1
    AND COUNT_IF(t.fruit = 'orange') OVER(PARTITION BY ID) = 1;

答案:

这可以通过以下方式完成:

select *
from data
qualify count( distinct iff(fruit in ('apple','banana','orange'), fruit, null)) 
           over(partition by id) = 1

给出:

ID FRUIT
personA avocado
personA banana
personA banana
personC melon
personC orange

工作原理:

可以通过显示 IFF and the COUNT DISTINCT 的中间状态来说明它是如何工作的,如下所示:

select *
    ,iff(fruit in ('apple','banana','orange'), fruit, null) as v
    ,count( distinct v) over(partition by id) as c
from data

给出:

ID FRUIT V C
personA avocado 1
personA banana banana 1
personA banana banana 1
personB apple apple 2
personB banana banana 2
personC melon 1
personC orange orange 1
personD grapefruit 0
personD pear 0

因此personD因没有魔法果实而被淘汰,personB因拥有过多而被淘汰

如果您非常关心性能(我会测试),我认为 nbk 的解决方案执行速度最快。