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 |
如果我没数错的话,我认为是对的。
值得注意:
- self-self 是该名称的总数,
- 还有 AB = BA 并且不再重复。
- 0 其中 Name1 和 Name2 没有共同的 ID
我的两个问题是:
- 如果我要google这个,这种操作叫什么?这是交叉表吗?某种支点?
- 我该怎么做?
- (额外的功劳,不仅适用于所有对,我将如何概括它以对所有三元组执行此操作?)
这是我的 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
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
- 自连接以将所有名称与所有其他名称进行匹配(这也是为了获得
Al
到 Steve
的匹配行);为避免双重配对(AB 和 BA),连接条件为 <=
- 计算所有出现的对,但只计算 ID 匹配的那些。如果这是在连接条件中完成的,那么就消除了
Al/Steve
配对,现在它与 COUNT = 0
. 一起出现
我有一个 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 |
如果我没数错的话,我认为是对的。
值得注意:
- self-self 是该名称的总数,
- 还有 AB = BA 并且不再重复。
- 0 其中 Name1 和 Name2 没有共同的 ID
我的两个问题是:
- 如果我要google这个,这种操作叫什么?这是交叉表吗?某种支点?
- 我该怎么做?
- (额外的功劳,不仅适用于所有对,我将如何概括它以对所有三元组执行此操作?)
这是我的 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
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
- 自连接以将所有名称与所有其他名称进行匹配(这也是为了获得
Al
到Steve
的匹配行);为避免双重配对(AB 和 BA),连接条件为<=
- 计算所有出现的对,但只计算 ID 匹配的那些。如果这是在连接条件中完成的,那么就消除了
Al/Steve
配对,现在它与COUNT = 0
. 一起出现