Запись, связанная со всеми записями другой таблицы в SQL.
-
17-09-2020 - |
Вопрос
Допустим, у нас есть три таблицы в реляционной базе данных:
Person {id, name}
Obstacle {id, name}
Person_overcomes_obstacle {person_id, obstacle_id}
Я хочу написать запрос, который сообщит мне, преодолел ли хотя бы один человек все препятствия.Идеи?
Решение
Я замечаю, что я был единственным человеком, чтобы использовать природную таблицу псевдоним для Person_overcomes_obstacle
!
Вам нужен Реляционный дивизион Запрос для этого.
Вы можете либо подсчитать препятствия, а соответствующие записи в Person_overComes_obstacle и возвращаемые, где 2 числа совпадают или посмотрите на него другой способ, находящиеся в поисках людей, для которых нет препятствий, которые они не преодолевают.
SELECT p.id, p.name /*Or use COUNT(*) or wrap in Exists
if you don't care about ids and names*/
FROM Person p
WHERE NOT EXISTS
(SELECT * FROM Obstacle o
WHERE NOT EXISTS
(
SELECT * FROM Person_overcomes_obstacle poo
WHERE poo.person_id = p.id and o.id = poo.obstacle_id
)
)
. Другие советы
SELECT
p.name,
COUNT(DISTINCT oo.obstacle_id) AS OBSTACLES_COMPLETED
FROM
person p
JOIN person_overcomes_obstacle oo
ON oo.person_id = p.person_id
GROUP BY
p.name
HAVING
COUNT(DISTINCT poo.obstacle_id) = (SELECT COUNT(id) FROM obstacle)
. Использовать:
SELECT poo.person_id
FROM PERSON_OVERCOMES_OBSTACLE poo
GROUP BY poo.person_id
HAVING COUNT(DISTINCT poo.obstacle_id) = (SELECT COUNT(*)
FROM OBSTACLE)
Это альтернатива, которая с меньшей вероятностью будет работать хорошо:
SELECT x.person_id
FROM (SELECT poo.person_id,
COUNT(DISTINCT poo.obstacle_id) AS obs_overcome,
(SELECT COUNT(*)
FROM OBSTACLE) AS obs_total
FROM PERSON_OVERCOMES_OBSTALCE poo
GROUP BY poo.person_id) x
WHERE x.obs_overcome = x.obs_total
В любом случае вы можете присоединиться к таблице PERSON, чтобы получить дополнительную информацию, если хотите, или вы можете выполнить подсчет person_id
из любого запроса, чтобы узнать, сколько человек преодолело все записанные препятствия.
Этот выбор должен вернуть количество препятствий, которые никто не преодолел.Если счет равен нулю, то все препятствия были преодолены хотя бы одним человеком.
SELECT count(*)
FROM (SELECT po.person_id, o.obstacle_id
FROM Obstacle o
LEFT OUTER JOIN Person_overcomes_obstacle po
ON (o.obstacle_id = po.obstacle_id)) t
WHERE t.person_id IS NULL
.
Вы также можете сделать это, для того же эффекта (и, возможно, лучшую производительность):
SELECT count(*)
FROM Obstacle o
WHERE NOT EXISTS (SELECT 1
FROM Person_overcomes_obstacle po
WHERE po.obstacle_id = o.obstacle_id)
.
Редактировать: Как указано в комментариях, вышеприведенные два запроса только доказывают, что нет препятствий, которые никто не преодолел, а не тот человек преодолел все препятствия.
Это кроме того, должно быть возможно, доказать, что один пользователь преодолел все препятствия без Запрос таблицы человека:
SELECT t.personid, count(*)
FROM (SELECT DISTINCT po.person_id, o.obstacle_id
FROM Obstacle o
JOIN Person_overcomes_obstacle po
ON (o.obstacle_id = po.obstacle_id)) t
GROUP BY t.persion_id
HAVING count(*) = (SELECT count(*)
FROM obstacle)
.