SQL查询以选择仅当它们共享完全相同的值对的成员:

huangapple go评论71阅读模式
英文:

SQL Query to select pairs of members only if they share the exact values

问题

I have the following table
members:

ID hobby
1 Football
1 Tennis
1 Football
2 Cards
2 Painting
3 Tennis
3 Football
4 Cards

and i want to select pairs of members only if they have the exact same hobbies (without duplicates).
So in the table above, i want the query to output:

id1 id2
1 3

my query:

SELECT m1.id as id1 , m2.id as id2
FROM members m1 inner join members m2
ON m1.id < m2.id
WHERE m1.hobby in (
  SELECT distinct(m2.hobby)
  )
GROUP BY id1,id2
英文:

I have the following table
members:

ID hobby
1 Football
1 Tennis
1 Football
2 Cards
2 Painting
3 Tennis
3 Football
4 Cards

and i want to select pairs of members only if they have the exact same hobbies (without duplicates).
So in the table above, i want the query to output:

id1 id2
1 3

my query:

SELECT m1.id as id1 , m2.id as id2
FROM members m1 inner join members m2
ON m1.id &lt; m2.id
WHERE m1.hobby in (
  SELECT distinct(m2.hobby)
  )
GROUP BY id1,id2

but i get:

id1 id2
1 3
2 4

答案1

得分: 1

以下是已翻译的内容:

一种做法是:

  • 计算每个ID拥有多少个唯一的爱好
  • 自连接以捕捉相同的爱好和一起的爱好数量,对不同的ID
  • 确保每个ID的爱好计数等于匹配记录的计数
WITH cte AS (
    SELECT ID, 
           hobby,
           COUNT(hobby) OVER(PARTITION BY ID) AS cnt
    FROM tab 
    GROUP BY ID, 
             hobby
)
SELECT t1.ID AS id1, 
       t2.ID AS id2
FROM       cte t1
INNER JOIN cte t2
        ON t1.ID < t2.ID 
       AND t1.hobby = t2.hobby
       AND t1.cnt = t2.cnt
GROUP BY t1.ID, t2.ID, t1.cnt
HAVING COUNT(*) = t1.cnt

输出

id1 id2
1 3

查看演示此处

英文:

One way of doing this is:

  • counting how many unique hobbies each ID has
  • self-joining to catch matching hobbies and number of hobbies together, on different ids
  • ensure the count of hobbies is equal to the count of matching records for each id
WITH cte AS (
    SELECT ID, 
           hobby,
           COUNT(hobby) OVER(PARTITION BY ID) AS cnt
    FROM tab 
    GROUP BY ID, 
             hobby
)
SELECT t1.ID AS id1, 
       t2.ID AS id2
FROM       cte t1
INNER JOIN cte t2
        ON t1.ID &lt; t2.ID 
       AND t1.hobby = t2.hobby
       AND t1.cnt = t2.cnt
GROUP BY t1.ID, t2.ID, t1.cnt
HAVING COUNT(*) = t1.cnt

Output:

id1 id2
1 3

Check the demo here.

答案2

得分: 0

你可以通过使用 GROUP_CONCAT 将兴趣按照成员 ID 进行分组,然后使用 SUBSTRING_INDEX 来拆分连接的对:

这个查询将返回具有多个成员的兴趣:

SELECT pairs
FROM (
  SELECT hobby, GROUP_CONCAT(DISTINCT ID) as pairs
  FROM members
  GROUP BY hobby
) as s
GROUP BY pairs
HAVING COUNT(pairs) > 1

结果:

pairs
1,3

然后,逗号分隔的对将在最终查询中转换为列:

WITH cte as (
  SELECT pairs
  FROM (
    SELECT hobby, GROUP_CONCAT(DISTINCT ID) as pairs
    FROM members
    GROUP BY hobby
  ) as s
  GROUP BY pairs
  HAVING COUNT(pairs) > 1
)
SELECT SUBSTRING_INDEX(pairs, ',', 1) AS ID1,
       SUBSTRING_INDEX(pairs, ',', -1) AS ID2
FROM cte

结果:

ID1    ID2
1      3

在这里查看演示

英文:

You can accomplish this by using GROUP_CONCAT to group ids by hobby and then splitting the concatenated pairs with SUBSTRING_INDEX:

This query will return the hobby with many members :

SELECT pairs
FROM (
  select hobby, GROUP_CONCAT(DISTINCT ID) as pairs
  from members
  group by hobby
) as s
GROUP BY pairs
HAVING COUNT(pairs) &gt; 1

Result :

pairs
1,3

The comma separated pairs will then be converted into columns in the final query :

WITH cte as (
  SELECT pairs
  FROM (
    select hobby, GROUP_CONCAT(DISTINCT ID) as pairs
    from members
    group by hobby
  ) as s
  GROUP BY pairs
  HAVING COUNT(pairs) &gt; 1
)
select SUBSTRING_INDEX(pairs, &#39;,&#39;, 1) AS ID1,
       SUBSTRING_INDEX(pairs, &#39;,&#39;, -1) AS ID2
from cte

Result :

ID1	ID2
1	3

Demo here

答案3

得分: 0

with data (id, hobby) as (
    select 1, '网球'  union all
    select 1, '足球'  union all
    select 1, '足球'  union all
    select 2, '纸牌游戏'  union all
    select 2, '绘画'  union all
    select 3, '网球'  union all
    select 3, '足球'  union all
    select 4, '纸牌游戏' union all
    select 5, '网球' union all
    select 5, '足球' union all
    select 5, '纸牌游戏'
)
, udata(id, hobby) as (
    select distinct id, hobby 
    from data
)
, cdata(id, n) as (
    select id, count(distinct hobby) as n
    from data
    group by id
)
select id1, id2 from (
    select u1.id as id1, u2.id as id2, count(*) as n, 
      c1.n as no1, c2.n as no2
    from udata u1
    join udata u2 on u2.id > u1.id and u1.hobby = u2.hobby
    join cdata c1 on c1.id = u1.id
    join cdata c2 on c2.id = u2.id
    group by u1.id, u2.id
) t
where n = no1 and n = no2
;
英文:
with data (id,hobby) as (
    select 1, &#39;Tennis&#39;  union all
    select 1, &#39;Football&#39;  union all
    select 1, &#39;Football&#39;  union all
    select 2, &#39;Cards&#39;  union all
    select 2, &#39;Painting&#39;  union all
    select 3, &#39;Tennis&#39;  union all
    select 3, &#39;Football&#39;  union all
    select 4, &#39;Cards&#39; union all
    select 5, &#39;Tennis&#39; union all
    select 5, &#39;Football&#39; union all
    select 5, &#39;Cards&#39;
)
, udata(id,hobby) as (
    select distinct id, hobby 
    from data
)
, cdata(id, n) as (
    select id, count(distinct hobby) as n
    from data
    group by id
)
select id1, id2 from (
    select u1.id as id1, u2.id as id2, count(*) as n, 
      c1.n as no1, c2.n as no2
    from udata u1
    join udata u2 on u2.id &gt; u1.id and u1.hobby = u2.hobby
    join cdata c1 on c1.id = u1.id
    join cdata c2 on c2.id = u2.id
    group by u1.id, u2.id
) t
where n = no1 and n = no2
;

(you could add count(distinct hobby) over(partition by id) as n in udata and add the condition on n in the JOIN between u1 and u2 later but MySQL doesn't support yet count distinct over partition…)

答案4

得分: 0

以下是翻译好的部分:

"一种简单的方法是使用字符串聚合。思路是构建每个成员所有爱好的列表;然后,我们可以自连接结果以生成共享完全相同列表的用户对。

with cte as (
    select id, group_concat(distinct hobby order by hobby) hobbies
    from members
    group by id
)
select c1.id as id1, c2.id as id2, c1.hobbies
from cte c1
inner join cte c2 on c1.hobbies = c2.hobbies and c1.id < c2.id

请注意,重要的是列表中的爱好进行排序,以便它们可以一致地进行比较。

id1 id2 hobbies
1 3 Football,Tennis

[fiddle](https://dbfiddle.uk/fcEmKiCb)"


<details>
<summary>英文:</summary>

One simple method uses string aggregation. The idea is to build a list of all hobbies of each member; we can then self-join the result to generate pairs of users that share the exact same list.

    with cte as (
        select id, group_concat(distinct hobby order by hobby) hobbies
        from members
        group by id
    )
    select c1.id as id1, c2.id as id2, c1.hobbies
    from cte c1
    inner join cte c2 on c1.hobbies = c2.hobbies and c1.id &lt; c2.id    
    
Note that it is important  to *order* the hobbies in the lists, so they can be consistently compared.

| id1 | id2 | hobbies |
|----:|----:|:--------|
| 1 | 3 | Football,Tennis |

[fiddle](https://dbfiddle.uk/fcEmKiCb)

</details>



huangapple
  • 本文由 发表于 2023年5月14日 21:26:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76247716.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定