Search code examples
mysqlsqlrelational-databaseinner-joinhaving-clause

MySQL query to find complete intersections


Imagine we have two tables:

  • clientOffices that have a list of offices that each client has.
  • clusters are groups of cities
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
-----------------------------

Now we want a query that tells us this: For each client, which what clusters are they FULLY present in? i.e. they have an office in EVERY city in the cluster?

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

I'm a MySQL Noob - tried different types of joins but couldn't get this result. It'd be great if you could help.

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


Solution

  • This will show all the client names that have complete cluster

    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