SQL - 计算如果 "category bucket" 被移除,有多少唯一 ID 会成为 w/o 一个类别

SQL - Count how many unique IDs would be w/o a category if "category bucket" was removed

我正在使用 Snowflake 来解决这个 SQL 问题,如果有任何独特的功能我可以使用,请帮助我!

我有一个包含唯一 ID 的数据集,其他不重要的属性,然后是每个唯一 ID 可能属于的类别列表 (~22)(如果它在类别中则用 1 表示,如果它在类别中则用 0 表示)如果没有。)

我想弄清楚如何写一些东西,我可以在其中查看是否跨所有类别,是否删除了某个类别,如果任何唯一 ID 将没有任何类别,并计算有多少唯一 ID 会然后做总共有多少 id 将被留在类别中。

下面的示例是唯一 ID Jshshsv,它仅在 CatAA 中,但 ID Hairbdb 在 CatY 和 CatAA 中。如果 CatAA 被删除,会有多少 ID 没有类别?

UniqueID Sum across Categories CatX CatY CatZ CatAA
Hairbdb 2 0 1 0 1
Jshshsv 1 0 0 0 1

出于某种原因,我无法弄清楚如何在 sql 中使用如此多的类别桶以可管理的方式执行此操作。任何提示或尝试的事情将不胜感激。

所以如果你的数据是成对的,有重复 身份证|猫 --|-- Hairbdb|猫Y Hairbdb|猫Y Hairbdb|CatAA Jshshsv|CatAA Jshshsv|CatAA

可以使用以下SQL来查找类别是ID的单个匹配项。

WITH data AS (
    SELECT * FROM VALUES
    ('Hairbdb','CatY'),
    ('Hairbdb','CatAA'),
    ('Jshshsv','CatAA')
    v(id, cat)
), dist_data AS (
    SELECT DISTINCT id, cat FROM data
), cat_counts AS (
    SELECT id, count(distinct cat) c_cat
    FROM data
    GROUP BY 1
    HAVING c_cat = 1
)  
SELECT a.cat, a.id
FROM dist_data AS a
JOIN cat_counts AS b 
    ON b.id = a.id;

这是可行的,因为你首先计算每个 id,id 属于多少类别,然后你将不同的数据与 id 只在一只猫中的数据相结合,会给你 id & cat

CAT ID
CatAA Jshshsv

如果你的数据是宽格式的(比如你如何呈现它),你可以像这样通过 UNPIVOT 把它变成我的表格:

WITH data AS (
    SELECT * FROM VALUES
    ('Hairbdb',0,1,0,1),
    ('Jshshsv',0,0,0,1)
    v(id, catx, caty, catz, cataa )
)
SELECT id, cat from data unpivot(catv for cat in (catx, caty, catz, cataa))
WHERE catv = 1;

给予:

ID CAT
Hairbdb CATY
Hairbdb CATAA
Jshshsv CATAA

但是如果它在您的表单中并且删除了重复项,您可以只使用 WHERE 子句:

WITH data AS (
    SELECT * from values
        ('Hairbdb', 0, 1, 0, 1),
        ('Jshshsv', 0, 0, 0, 1)
     v(UniqueID, CatX,CatY,CatZ, CatAA) 
)
SELECT UniqueID,
    CatX+CatY+CatZ+CatAA as "Sum across Categories",
    CatX,
    CatY,
    CatZ,
    CatAA  
FROM data
WHERE "Sum across Categories" = 1;

所以另一种变体,如果每个 id 有很多行,并且整个集合中的类别分配不相同,则可以使用 COUNT_IF 和大于 0 的测试将数据转换为a in any,然后使用HAVING子句过滤掉那些在许多列中的那些

WITH data AS (
    SELECT * FROM VALUES
    ('Hairbdb',0,1,0,1),
    ('Hairbdb',1,1,0,1),
    ('Hairbdb',0,1,1,1),
    ('Jshshsv',0,0,0,1),
    ('Jshshsv',0,0,0,1)
    v(id, catx, caty, catz, cataa )
)
SELECT id, 
    COUNT_IF(catx=1)>0 AS catx_a,
    COUNT_IF(caty=1)>0 AS caty_a,
    COUNT_IF(catz=1)>0 AS catz_a,
    COUNT_IF(cataa=1)>0 AS cataa_a
FROM data
GROUP BY 1
HAVING catx_a::int + caty_a::int + catz_a::int + cataa_a::int = 1;

如果您将类别存储在列中(虽然不是一个好的设计),您可以试试这个。

SELECT UniqueID ,  sum(CatX+CatY+CatZ+CatAA)   over (partition by UniqueID) as "Sum across Categories",
 CatX,   CatY,  CatZ, CatAA  FROM (
SELECT 'Hairbdb' as UniqueID,   0 as CatX,  1 as CatY,  0 as CatZ,  1 as CatAA from dual
UNION ALL 
SELECT 'Jshshsv',   0,0,0,1 from dual 
);