Как я могу сделать запрос SQL, который возвращает ноль, если нет записи, или вернуть значение, если есть? - PullRequest
0 голосов
/ 15 ноября 2018

Я пытаюсь сделать запрос по трем различным таблицам.

  1. Таблица переменных

    • Таблица переменных содержит информацию о том, что "area", "rounds" и "days" переменная принадлежит. Таблица переменных также содержит столбец pk. ПК используется для определения, к какой переменной относится запись.
  2. Таблица площадей

    • Таблица области содержит информацию о "name" области, а также "role" область принадлежит. Пользователь назначается роль, а затем имеет доступ к определенным областям.
  3. Таблица рекордов

    • Таблица записей содержит информацию о записи, которая была введена. Это содержит столбцы "value", "alarmed" и "alarmType". Вы можете искать для записи, основанной на переменной, раунде и дне.

Я пытаюсь запросить все переменные за определенный раунд и день для пользователя. Я хочу отобразить все переменные независимо от того, найдена ли запись. В настоящее время у меня есть запрос, который возвращает только те переменные, которые имеют записи, но не те, которые не имеют.

Если записи нет, столбец value, alarmed, and alarmType должен быть нулевым.

Это запрос, который я до сих пор построил:

SELECT DISTINCT variable.name, area.name AS "areaName", variable.pk, CAST(record.value AS TEXT) AS "value", record.alarmed, record.alarmType 
FROM variable, area, record 
WHERE variable.round LIKE '%,1,%' 
  AND variable.day LIKE '%,3,%' 
  AND variable.readOnly = 0 
  AND variable.area IN (SELECT pk 
                        FROM area 
                        WHERE role = (SELECT role 
                                      FROM user 
                                      WHERE userName LIKE 'Leo')) 
  AND variable.area = area.pk 
  AND record.value = (SELECT CASE WHEN COUNT() < 1 THEN NULL 
                             ELSE CAST(value AS TEXT) END 
                      FROM record 
                      WHERE round = 1 
                        AND day = "11-14-2018" 
                        AND variable = variable.pk) 
ORDER BY variable.area, variable.position ASC;

В настоящее время он возвращает что-то вроде этого:

What this query returns

Переменных гораздо больше, и я хочу знать, как их отображать, даже если нет записей.

1 Ответ

0 голосов
/ 15 ноября 2018

Мне кажется, я вижу, что ты пытаешься сделать. Ключ в том, чтобы использовать объединения (в частности, соединения 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).

...