【问题标题】:Calculating overlap between groups计算组之间的重叠
【发布时间】:2026-01-07 21:25:09
【问题描述】:

我有一个包含两列感兴趣的表,item_idbucket_idbucket_id 有固定数量的值,如果需要,我可以列出它们。

每个item_id 可以出现多次,但每次出现都会有一个单独的bucket_id 值。例如,123item_id 可以在表格中出现两次,一次在Abucket_id 下,一次在B 下。

我的目标是确定每对 bucket_id 值之间存在多少重叠,并将其显示为 N×N 矩阵。

例如,考虑以下小示例表:

item_id     bucket_id
=========   ===========
111         A
111         B
111         C

222         B
222         D

333         A
333         C

444         C

所以对于这个数据集,桶 AB 有一个共同的 item_id,桶 CD 没有共同的项目,等等。

我想将上面的表格格式化成如下格式:

        A       B       C       D
===================================
A       2       1       2       0
B       1       2       1       1
C       2       1       3       0
D       0       1       0       1

在上表中,行和列的交集告诉您两个bucket_id 值中存在多少条记录。例如,在A 行与C 列相交的地方,我们有一个2,因为bucket_id A 和C 中都存在2 条记录。因为X 和Y 的交集与Y 和 X 的交点,上表是对角线的镜像。

我认为查询涉及PIVOT,但我终其一生都无法弄清楚如何让它工作。

【问题讨论】:

  • 最后一个表代表什么(例如,A 行 C 列的值 2 代表什么)?
  • @John - 我在表格下方添加了更多解释。
  • 这是一种度量标准。但令人困惑

标签: sql oracle oracle11g pivot


【解决方案1】:

您可以使用简单的 PIVOT:

SELECT t1.bucket_id,
       SUM( CASE WHEN t2.bucket_id = 'A' THEN 1 ELSE 0 END ) AS A,
       SUM( CASE WHEN t2.bucket_id = 'B' THEN 1 ELSE 0 END ) AS B,
       SUM( CASE WHEN t2.bucket_id = 'C' THEN 1 ELSE 0 END ) AS C,
       SUM( CASE WHEN t2.bucket_id = 'D' THEN 1 ELSE 0 END ) AS D
FROM table1 t1
JOIN table1 t2 ON t1.item_id = t2.item_id
GROUP BY t1.bucket_id
ORDER BY 1
;

或者您可以使用 Oracle PIVOT 子句(适用于 11.2 及更高版本):

SELECT * FROM (
   SELECT t1.bucket_id AS Y_bid,
          t2.bucket_id AS x_bid
   FROM table1 t1
   JOIN table1 t2 ON t1.item_id = t2.item_id
)
PIVOT (
  count(*) FOR x_bid in ('A','B','C','D')
)
ORDER BY 1
;

示例:http://sqlfiddle.com/#!4/39d30/7

【讨论】:

    【解决方案2】:

    我相信这应该可以为您提供所需的数据。然后可以以编程方式(或在 Excel 等中)完成表格的透视。

    -- This gets the distinct pairs of buckets
    select distinct
        a.name,
        b.name
    from
        bucket a
        join bucket b
    where
        a.name < b.name
    order by
        a.name,
        b.name
    
    + --------- + --------- +
    | name      | name      |
    + --------- + --------- +
    | A         | B         |
    | A         | C         |
    | A         | D         |
    | B         | C         |
    | B         | D         |
    | C         | D         |
    + --------- + --------- +
    6 rows
    
    -- This gets the distinct pairs of buckets with the counts you are looking for
    select distinct
        a.name,
        b.name,
        count(distinct bi.item_id)
    from
        bucket a
        join bucket b
        left outer join bucket_item ai on ai.bucket_name = a.name
        left outer join bucket_item bi on bi.bucket_name = b.name and ai.item_id = bi.item_id
    where
        a.name < b.name
    group by
        a.name,
        b.name
    order by
        a.name,
        b.name
    
    + --------- + --------- + ------------------------------- +
    | name      | name      | count(distinct bi.item_id)      |
    + --------- + --------- + ------------------------------- +
    | A         | B         | 2                               |
    | A         | C         | 1                               |
    | A         | D         | 0                               |
    | B         | C         | 2                               |
    | B         | D         | 0                               |
    | C         | D         | 0                               |
    + --------- + --------- + ------------------------------- +
    6 rows
    

    这是带有 DDL 和插入设置的整个示例(这是在 mysql 中,但相同的想法适用于其他地方):

    use example;
    
    drop table if exists bucket;
    
    drop table if exists item;
    
    drop table bucket_item;
    
    create table bucket (
        name varchar(1)
    );
    
    create table item(
        id int
    );
    
    create table bucket_item(
        bucket_name varchar(1) references bucket(name),
        item_id int references item(id)
    );
    
    insert into bucket values ('A');
    insert into bucket values ('B');
    insert into bucket values ('C');
    insert into bucket values ('D');
    
    insert into item values (111);
    insert into item values (222);
    insert into item values (333);
    insert into item values (444);
    insert into item values (555);
    
    insert into bucket_item values ('A',111);
    insert into bucket_item values ('A',222);
    insert into bucket_item values ('A',333);
    insert into bucket_item values ('B',222);
    insert into bucket_item values ('B',333);
    insert into bucket_item values ('B',444);
    insert into bucket_item values ('C',333);
    insert into bucket_item values ('C',444);
    insert into bucket_item values ('D',555);
    
    
    -- query to get distinct pairs of buckets
    select distinct
        a.name,
        b.name
    from
        bucket a
        join bucket b
    where
        a.name < b.name
    order by
        a.name,
        b.name
    ;
    
    select distinct
        a.name,
        b.name,
        count(distinct bi.item_id)
    from
        bucket a
        join bucket b
        left outer join bucket_item ai on ai.bucket_name = a.name
        left outer join bucket_item bi on bi.bucket_name = b.name and ai.item_id = bi.item_id
    where
        a.name < b.name
    group by
        a.name,
        b.name
    order by
        a.name,
        b.name
    ;
    

    【讨论】:

      最近更新 更多