MySQL 查询以找到完整的交叉点
MySQL query to find complete intersections
假设我们有两个表:
clientOffices
有每个客户拥有的办公室列表。
clusters
是城市组
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;
这看起来像是一个关系除法问题。我会把它写成聚合查询,在 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 |
假设我们有两个表:
clientOffices
有每个客户拥有的办公室列表。clusters
是城市组
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;
这看起来像是一个关系除法问题。我会把它写成聚合查询,在 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 |