MySQL 查询以找到完整的交叉点

MySQL query to find complete intersections

假设我们有两个表:

clientOffices
-----------------------------
clientId    |   office
-----------------------------
1               London
1               Manchester
1               Edinburgh
1               Bonn
2               London
2               Frankfurt
2               Bonn
3               Manchester
3               Frankfurt
-----------------------------       



clusters
-----------------------------
clusterName |   city
-----------------------------
X               London      
X               Manchester
Y               Manchester
Y               Frankfurt
Y               Bonn
Z               London
Z               Bonn
-----------------------------

现在我们需要一个查询来告诉我们: 对于每个客户端,它们完全存在于哪些集群中? 即他们在集群中的每个城市都有办事处?

Desired result:
-------------------------------------------
clientOffices.clientId  |   clusters.clusterName
-------------------------------------------
1                               X
1                               Z
2                               Z
3                               Null
--------------------------------------------

我是 MySQL 菜鸟 - 尝试了不同类型的连接,但无法获得此结果。如果你能帮上忙那就太好了。

fiddle: https://www.db-fiddle.com/f/2GTBVXm9StNHcyuSqSZikW/0

这将显示所有具有完整集群的客户端名称

SELECT DISTINCT a.clientName, a.clusterName
FROM
(
    SELECT clientOffices.clientName, clusters.clusterName, COUNT(*) AS counts
    FROM clientOffices
    LEFT JOIN clusters ON clusters.city = clientOffices.office
    GROUP BY clientOffices.clientName, clusters.clusterName
) AS a
JOIN
(
    SELECT clusterName, COUNT(*) AS counts
    FROM clusters
    GROUP BY clusterName
) AS b
ON a.clusterName = b.clusterName AND a.counts = b.counts

UNION

SELECT c.clientName, null AS clusterName FROM
(
  SELECT  a.clientName, COUNT(*) as invalid_office
FROM
(
    SELECT clientOffices.clientName, clusters.clusterName, COUNT(*) AS counts
    FROM clientOffices
    LEFT JOIN clusters ON clusters.city = clientOffices.office
    GROUP BY clientOffices.clientName, clusters.clusterName
) AS a
JOIN
(
    SELECT clusterName, COUNT(*) AS counts
    FROM clusters
    GROUP BY clusterName
) AS b
ON a.clusterName = b.clusterName AND a.counts != b.counts
  GROUP BY a.clientName
) AS c
JOIN
(
    SELECT clientName, COUNT(*) AS office_count
    FROM clientOffices
    GROUP BY clientName
) AS d
ON c.clientName = d.clientName AND c.invalid_office = d.office_count;

https://www.db-fiddle.com/f/6jKvKXPYvsLeXgm3Qv1nHu/10

这看起来像是一个关系除法问题。我会把它写成聚合查询,在 having 子句中进行过滤:

select co.clientid, cl.clusterName
from clientoffices co
inner join clusters cl on cl.city = co.office
group by co.clientid, cl.clusterName
having count(*) = (select count(*) from clusters cl1 where cl1.clusterName = cl.clusterName)

对于您的示例数据 this produces:

| clientid | clusterName |
| -------- | ----------- |
| 1        | X           |
| 1        | Z           |
| 2        | Z           |