Мне кажется, я вижу, что ты пытаешься сделать. Ключ в том, чтобы использовать объединения (в частности, соединения OUTER) вместо того, чтобы пытаться объединить все таблицы вместе и затем найти сходства. Существуют также вкусы LEFT
, RIGHT
и INNER
(подробнее об этих здесь и здесь ), в зависимости от того, что вы считаете "полным" или "основным" набор данных - отправная точка вашего запроса.
Вот как я понимаю ваши отношения (дайте мне знать, если я ошибаюсь):
record.variable --> variable.pk
variable.area --> area.pk
area.role --> user.role
В вашем случае вы заявили, что вам нужны все записи из таблицы variable
, поэтому я бы начал с этого:
SELECT v.*
FROM variable v;
Затем вы можете найти все записи AREA, связанные с конкретным пользователем. Используйте INNER
объединение, чтобы найти только записи, которые существуют на ОБА сторон объединения:
SELECT a.*, u.*
FROM area a
INNER JOIN user u -- Define the table to join
ON a.role = u.role -- Which columns contain keys to match on
WHERE u.userName = 'Leo';
Фильтр WHERE применяется к таблице user
, но, поскольку мы ТОЛЬКО запрашиваем записи из таблицы area
, которые совпадают с пользователем, это ограничивает результаты из таблицы area
.
Следующий шаг - объединить эти два экстракта, используя еще одно INNER
соединение, снова, чтобы найти пересечение - совпадения, которые существуют на ОБА сторонах соединения:
SELECT v.*, a.*, u.*
FROM variable v -- New starting point
INNER JOIN area a
ON a.pk = v.area
INNER JOIN user u
ON a.role = u.role
WHERE u.userName = 'Leo';
Теперь мы находим все записи за определенный день, добавляя WHERE
предложения:
SELECT v.*, a.*, u.*
FROM variable v
INNER JOIN area a
ON a.pk = v.area
INNER JOIN user u
ON a.role = u.role
WHERE u.userName = 'Leo'
AND v.round = 1 -- Add filters for "round"
AND v.day = '11-14-2018'; -- and "day" columns
Затем мы используем объединение LEFT
, чтобы получить все записи из таблицы «слева» плюс любые совпадения, которые мы находим с «правой» стороны (таблица «запись»), или NULL, если совпадения не найдено. сделано:
SELECT v.name
,a.name as "areaName"
,CAST(r.value as TEXT) as "value"
,r.alarmed
,r.alarmType
FROM variable v
INNER JOIN area a
ON v.area = a.pk
INNER JOIN user u
ON a.role = u.role
LEFT JOIN record r -- LEFT is important here
ON v.pk = r.variable
WHERE u.userName = 'Leo'
AND v.round = 1
AND v.day = '11-14-2018'
ORDER BY v.area, v.position;
Результат от INNER
объединений (variable
+ area
+ user
) становится «левой» стороной этого объединения, а record
становится «правой» стороной. Использование LEFT
объединения объявляет, что мы хотим ВСЕ записи слева, независимо от того, совпадают ли они справа или нет.
У меня нет набора данных для тестирования, поэтому прошу прощения за любые ошибки, которые я сделал.
Надеюсь, это иллюстрирует, как объединения будут использоваться как для удаления строк, так и для добавления данных (столбцов) результата, без необходимости делать отдельные запросы или прибегать к подзапросам (используя IN
или EXISTS
).