Skip to content
Advertisement

Select everything that has only one value in a relation

Okay, so here are my tables: tests:

+----+------------+
| id | name       |
+----+------------+
|  1 | test-one   |
|  2 | test-two   |
|  3 | test-three |
|  4 | test-four  |
|  5 | test-five  |
|  6 | test-six   |
+----+------------+

testGroups:

+----+-------------+
| id | name        |
+----+-------------+
|  1 | group-one   |
|  2 | group-two   |
|  3 | group-three |
|  4 | group-four  |
|  5 | group-five  |
|  6 | group-six   |
|  7 | group-seven |
|  8 | group-eight |
|  9 | group-nine  |
| 10 | group-ten   |
+----+-------------+

and testGroupAssignments

+----+--------+---------+
| id | testID | groupID |
+----+--------+---------+
|  1 |      1 |       1 |
|  2 |      2 |       1 |
|  3 |      2 |       2 |
|  4 |      2 |       3 |
|  5 |      3 |       1 |
|  6 |      3 |       3 |
|  7 |      4 |       1 |
|  8 |      5 |       6 |
|  9 |      5 |       7 |
| 10 |      5 |       4 |
+----+--------+---------+

What I want is to get every test that has group-one assigned to it, given it has no other group assigned to it.

+--------+-----------+
| testID | testName  |
+--------+-----------+
|      1 | test-one  |
|      4 | test-four |
+--------+-----------+

I know that I should use a LEFT JOIN and I tried to do:

SELECT
    t.id `testID`,
    t.name `testName`
FROM
    tests `t`
INNER JOIN
    testGroupAssignments `tga`
ON
    t.id = tga.testID
LEFT JOIN
    testGroupAssignments `tga2`
ON
    t.id = tga.testID AND tga2.groupID != 1
INNER JOIN
    testGroups `tg`
ON
    tg.id = tga.groupID
WHERE
    tga.groupID = 1
AND
    tga2.groupID != 1
AND
    tga2.groupID IS NULL

Advertisement

Answer

You can try the following:

SELECT t.id AS testID, t.name AS testName
FROM tests t
  INNER JOIN testGroupAssignments tga ON t.id = tga.testID
  INNER JOIN testGroups tg ON tg.id = tga.groupID
WHERE tga.groupID = 1 AND NOT EXISTS (
  SELECT 1 
  FROM testGroupAssignments 
  WHERE testID = t.id AND groupID <> 1
)

In case you don’t want to show column values of the other tables you can use the following simple query:

SELECT * 
FROM tests t 
WHERE EXISTS (
  SELECT 1 
  FROM testGroupAssignments tga 
  WHERE tga.testID = t.id AND tga.groupID = 1
) AND NOT EXISTS (
  SELECT 1 
  FROM testGroupAssignments tga 
  WHERE tga.testID = t.id AND tga.groupID <> 1
)

demo on dbfiddle.uk

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement