问题描述
我有一张看起来像这样的桌子
| 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
我的两个问题是:
这是我的 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'),'Jim'),('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 |
这不是我想要的,因为它缺少零。
解决方法
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
一起出现。
您可以按如下方式使用 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