SQL 中的邻接列表中的成对计数共享另一个字段的相同值

Paired counts sharing the same value of another field into an adjacency list in SQL

我有一个 table 看起来像这样

| id | name  |
|  A | Fred  |
|  A | Steve |
|  B | Al    |
|  B | Fred  |
|  B | Jim   |
|  C | Steve |
|  C | Jim   |

我正在寻找一个查询,该查询将按对所有对共享相同 ID 的名称对汇总 ID 计数。

也就是说,我想要的查询将其转换为:

| name1 | name2 | value |
| Al    | Al    |     1 |
| Al    | Jim   |     1 |
| Al    | Fred  |     1 |
| Al    | Steve |     0 |
| Fred  | Fred  |     2 |
| Fred  | Jim   |     1 |
| Fred  | Steve |     1 |
| Jim   | Jim   |     2 |
| Jim   | Steve |     1 |
| Steve | Steve |     2 |

如果我没数错的话,我认为是对的。

值得注意:

我的两个问题是:

  1. 如果我要google这个,这种操作叫什么?这是交叉表吗?某种支点?
  2. 我该怎么做?
  3. (额外的功劳,不仅适用于所有对,我将如何概括它以对所有三元组执行此操作?)

这是我的 db-fiddle 开始:

https://www.db-fiddle.com/f/fXffVUHyhTTBGrJRrvYPrx/0

作为:

create table People (
  id text,
  name text
  );
  
insert into People( 
  id, name) VALUES 
    ('A', 'Fred'),
    ('A', 'Steve'),
    ('B', 'Al'),
    ('B', 'Fred'),
    ('B', 'Jim'),
    ('C', 'Steve'),
    ('C', 'Jim');
   
SELECT  a.name as name1, 
        b.name as name2, 
        count(*) as value
   FROM People a
   JOIN People b on a.id = b.id
   WHERE a.name <= b.name
   group by name1, name2;

不幸的是,这会产生:

| name1 | name2 | value |
| ----- | ----- | ----- |
| Al    | Al    | 1     |
| Al    | Fred  | 1     |
| Al    | Jim   | 1     |
| Fred  | Fred  | 2     |
| Fred  | Jim   | 1     |
| Fred  | Steve | 1     |
| Jim   | Jim   | 2     |
| Jim   | Steve | 1     |
| Steve | Steve | 2     |

这不是我要找的,因为它缺少零。

您可以按如下方式使用 distinct 名称和 LEFT JOIN

with all_people as (select distinct name from people) 
select a.name, b.name, count(case when pa.id = pb.id then 1 end)
  from all_people a
  join all_people b on a.name <= b.name
  left join people pa on a.name = pa.name
  left join people pb on b.name = pb.name
group by a.name, b.name
order by a.name

Demo

demo:db<>fiddle

SELECT
    p1.name, p2.name,
    COUNT(*) FILTER (WHERE p1.id = p2.id)      -- 2
FROM people p1
    LEFT JOIN people p2 ON p1.name <= p2.name  -- 1
GROUP BY p1.name, p2.name
  1. 自连接以将所有名称与所有其他名称进行匹配(这也是为了获得 AlSteve 的匹配行);为避免双重配对(AB 和 BA),连接条件为 <=
  2. 计算所有出现的对,但只计算 ID 匹配的那些。如果这是在连接条件中完成的,那么就消除了 Al/Steve 配对,现在它与 COUNT = 0.
  3. 一起出现