Выберите все, что имеет только одно значение в отношении - PullRequest
0 голосов
/ 28 января 2020

Хорошо, вот мои таблицы: 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   |
+----+-------------+

и 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 |
+----+--------+---------+

Что я хочу получить каждый test, которому назначено group-one, учитывая, что ему не назначена никакая другая группа.

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

Я знаю, что должен использовать LEFT JOIN, и я пытался сделать:

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

Ответы [ 3 ]

1 голос
/ 28 января 2020

Вы можете попробовать следующее:

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
)

Если вы не хотите показывать значения столбцов других таблиц, вы можете использовать следующий простой запрос:

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
)

демо на dbfiddle.uk

0 голосов
/ 28 января 2020

использовать self join к таблице testgroupassigments попробуйте это.

SELECT t.id AS Testgroupassignments_id,
test.`name` AS Test_name,
testg.`name` AS Test_group_name
FROM  stackoverflow.testgroupassignments AS t
LEFT JOIN stackoverflow.tests AS test ON test.id = t.testID
LEFT JOIN stackoverflow.testgroups AS testg ON testg.id = t.groupID
WHERE t.id  NOT IN (
SELECT ta.id FROM
stackoverflow.testgroupassignments AS ta
LEFT JOIN  stackoverflow.testgroupassignments AS taa ON taa.testID = ta.testID
WHERE ta.id <> taa.id )
0 голосов
/ 28 января 2020

Вы можете выполнить агрегацию с помощью JOIN:

SELECT ts.id AS testID, ts.name AS testName 
FROM tests ts INNER JOIN
     testGroupAssignments tg
     ON tg.testID = ts.id
GROUP BY ts.id, ts.name
HAVING COUNT(tg.groupID) = 1;

Если у вас есть дубликат groupID s, используйте DISTINCT внутри COUNT().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...