Статья: Синтаксический сахар SQL — функция COALESCE
Если Вы работаете с SQL, то скорее всего Вы сталкивались с выражением COALESCE. Если же Вы с ним не знакомы, то самое время сделать это сейчас — это очень крутая штука, которая пригодится Вам в решении большого количества задач.
Итак, начнем с самого простого — что такое COALESCE?
Определение
COALESCE — это специальное выражение, которое вычисляет по порядку каждый из своих аргументов и на выходе возвращает значение первого аргумента, который был не NULL.
Пример:
SELECT COALESCE(NULL, NULL, 1, 2, NULL, 3)
# 1
Этот запрос вернет 1, потому что первые два аргумента NULL
, а третий аргумент принимает значение отличное от NULL
. Соответственно, выражение COALESCE
даже не будет смотреть дальше — главное, что 3 аргумент не NULL
.
Другие примеры:
SELECT COALESCE(1, NULL, 2, NULL)
# 1
или
SELECT COALESCE(NULL, NULL)
# NULL
Наверно, вы поняли основной смысл. Если можно вернуть не NULL
— возвращается первое непустое значение. Если нельзя — возвращается NULL
Стоит отметить, что COALESCE используется во многих популярных СУБД: PostgreSQL, MS SQL Server, Oracle, MySQL и так далее.
Давайте теперь копнем чуть глубже и посмотрим, как же это выражение устроено.
Аналогия с CASE
Мы разобрались, как выражение COALESCE
работает, но сможем ли мы написать его с нуля? Допустим, нам дали задание:
Не используя COALESCE, напишите SELECT-запрос, который будет аналогичен запросу SELECT COALESCE(expression1, expression2, expression3, expression4)
Сможете решить такую задачу сходу? На самом деле, еще решение довольно простое: COALESCE
— это просто удобная обертка для конструкции CASE
. Ее удобно использовать для обработки значений
.
Учитывая, что обработка пропусков — типовая задача при написании SQL-запросов, решили выделить эту конструкцию в отдельное выражение COALESCE
, чтобы бедные разработчики не мучались каждый раз и не громоздили огромные CASE
-выражения.
Давайте же и мы с вами решим эту задачу. Ответ будет такой:
SELECT CASE WHEN (expression1 IS NOT NULL) THEN expression1 WHEN (expression2 IS NOT NULL) THEN expression2 WHEN (expression3 IS NOT NULL) THEN expression3 ELSE expression4 END
Вот, собственно, и все премудрости. Согласитесь — не сложно. Но значительно удобней писать COALESCE
, чем каждый раз записывать такую объемную конструкцию с CASE
.
Боевая задача
Давайте на реальном примере рассмотрим, когда использование COALESCE — не просто желание побаловаться, а реальная необходимость.
Вы можете сказать:
Я столько времени пишу SQL-запросы и ни разу не пользовался COALESCE!
Ну, что же, возможно Вам просто везло… Но с высокой долей вероятности некоторые Ваши запросы начнут выдавать неправильные результаты, если таблицы начнут заполняться «некрасивыми» данными.
Рассмотрим простую задачу. Пусть есть бухгалтерская таблица, в которой содержится информация о имени сотрудника и его ежемесячной премии. В конце года перед нами встала тривиальная задачка (на первый взгляд) — посчитать суммарный заработок каждого сотрудника.
+--------+----------+-----------+--------------+ | ID | name | bonus | date | +--------+----------+-----------+--------------+ | 1 | Ivan | NULL | 2020-01-01 | | 1 | Maya | 3500 | 2020-01-03 | | 1 | Dora | 4500 | 2020-01-02 | | 1 | Petr | 5750 | 2020-02-01 | | 1 | Ivan | 3220 | 2020-03-05 | | ... | +--------+----------+-----------+--------------+
Так получилось, что у сотрудника Ivan
не прогрузился бонус за январь и в таблице стоит значение NULL
. Соответственно, приведенный ниже запрос вернет 3220
для этого сотрудника.
SELECT name, SUM(bonus)
FROM table_name
GROUP BY name
Мало того, что результат получился неверным — мы об этом даже не узнаем. А если записей много, то различные расчеты и агреграции постоянно будут приводить к скрытым ошибкам (проверено на практике).
Чтобы такой ситуации избежать, можно заменять значения NULL на очень большое число, например. Тогда мы в качестве результата будем получать премию в несколько миллиардов и понимать, что что-то здесь не так.
Естественно, в зависимости от задачи приемы могут быть разные: этот пример иллюстрирует ручную обработку таблицы с премиями.
В нашем же случае решение можно записать так:
SELECT name, SUM(COALESCE(bonus, 1000000))
FROM table_name
GROUP BY name
Эпилог
Мы рассмотрели выражение COALESCE
и показали его важность. Посмотрите на те запросы, которые Вы пишите каждый день — нет ли там места ошибке? Может и у Вас могут возникнуть какие-то ситуации, когда расчет будет неправильным, а Вы даже не сможете этого увидеть? Чтобы избежать таких ситуаций, используйте COALESCE
!
7 распространенных ошибок в SQL-запросах, которые делал каждый (почти) / Хабр
Сегодня SQL используют уже буквально все на свете: и аналитики, и программисты, и тестировщики, и т. д. Отчасти это связано с тем, что базовые возможности этого языка легко освоить.
Однако работая с большим количеством junior-ов, мы раз от раза находим в их решениях одни и те же ошибки. Реально — иногда просто создается ощущение, что они копируют друг у друга код.
Кстати, иногда такая же участь постигает и специалистов более высокого полета.
Сегодня мы решили собрать 7 таких ошибок в одном месте, чтобы как можно меньше людей их совершали.
Примечание: Ошибки будут 2 видов — реальные ошибки и своего рода best practices, которым часто не следуют.
Но, обо всем по порядку 🙂
Кстати, будем рады видеть вас в своих социальных сетях — ВКонтакте Телеграм Инстаграм
1. Преобразование типов
Мы привыкли, что в математике мы всегда можем разделить одно число на другое и получить ответ. Если нацело не получается, то в виде дроби.
В SQL это не всегда так работает. Например, в PostgreSQL деление двух целых чисел друг на друга даст целочисленный ответ. Это можно проверить как для целочисленных столбцов, так и для чисел.
SELECT a/b FROM demo # столбец целых чисел SELECT 1 / 2 # 0
Аналогичные запросы, например, в MySQL дадут дробное число, как и положено.
Если Вы точно не уверены или хотите подстраховаться, то лучше всегда явно делать преобразование типов. Например:
SELECT a::NUMERIC/b FROM demo SELECT a*1.0/b FROM demo SELECT CAST(1 AS FLOAT)/2 FROM demo
Все перечисленные примеры дадут нужный ответ.
2. HAVING вместо WHERE
Часто встречается ошибка — оператор HAVING используется вместо WHERE в запросах с агрегацией. Это неверно!
WHERE производит фильтрацию строк в исходном наборе данных, отсеивая неподходящие. После этого GROUP BY формирует группы и оператор HAVING производит фильтрацию уже целых групп (будто группа — одно запись).
Например:
SELECT date, COUNT(*) FROM transactions t WHERE date >= '2019-01-01' GROUP BY date HAVING COUNT(*) = 2
Здесь мы сначала отсеиваем строки, в которых хранятся записи до 2019 года.
Некоторые же пишут так:
SELECT date, COUNT(*) FROM transactions t GROUP BY date HAVING COUNT(*) = 2 AND date >= '2019-01-01'
Так делать не нужно 🙂
Кстати, для закрепления этой темы мы специально делали задачку «Отфильтрованные продажи» у себя на платформе. Если интересно порешать и другие задачки по SQL — welcome 🙂
3. Алиасы и план запроса
Если «проговаривать SQL-запрос» словами, то получится что-то такое:
В таблице есть старая цена, а есть новая цена. Их разность я назову diff. Я хочу отобрать только те строки, где значение diff больше 100.
Звучит вполне логично. Но в SQL прям так реализовать не получится — и многие попадаются в эту ловушку.
Вот неправильный запрос:
SELECT old_price - new_price AS diff FROM goods WHERE diff > 100
Ошибка его заключается в том, что мы используем алиас столбца diff внутри оператора WHERE.
Да, это выглядит вполне логичным, но мы не можем так сделать из-за порядка выполнения операторов в SQL-запросе. Дело в том, что фильтр WHERE выполняется сильно раньше оператора SELECT (а значит и AS). Соответственно, в момент выполнения столбца diff просто не существует. Об этом, кстати, и говорит ошибка:
ERROR: column "diff" does not exist
Правильно будет использовать подзапрос или переписать запрос следующим образом:
SELECT old_price - new_price AS diff FROM goods WHERE old_price - new_price > 100
Важно: Внутри ORDER BY вы можете указывать алиас — этот оператор выполняется уже после SELECT.
Кстати, мы тут делали карточку, где наглядно показывается последовательность выполнения операторов. Возможно, это вам пригодится.
4. Не использовать COALESCE
Пришло время неочевидных пунктов. Но сейчас мы поясним свои чаяния.
COALESCE — это оператор, который принимает N значений и возвращает первое, которое не NULL. Если все NULL, то вернется NULL.
Нужен этот оператор для того, чтобы в расчеты случайно не попадали пропуски. Такие пропуски всегда сложно заметить, потому что при расчете среднего на основании ста тысяч строк вы вряд ли заметите подвох, даже если 1000 просто будет отсутствовать. Обычно такие численные пропуски заполняют средними значениями/минимальными/максимальными/медианными/средними или с помощью какой-то интерполяции — зависит от задачи.
Мы же рассмотрим нечисловой пример, а вполне себе бизнесовый. Например, есть таблица клиентов Clients. В поле name заносится имя пользователя.
Отдел маркетинга решил сделать email-рассылку, которая начинается с фразы:
Приветствуем, имя_пользователя!
Очевидно, что если name is NULL, то это превратится в тыкву:
Приветствуем, !
Вот в таких случаях и помогает COALESCE:
SELECT COALESCE(name, 'Дорогой друг') FROM Clients
Совет: Лучше всегда перестраховываться. Особенно это касается вычислений и агрегирований — там вы не найдете ошибку примерно никогда, так что лучше подложить соломку.
5. Игнорирование CASE
Если вы используете CASE, то иногда вы можете сократить свои запросы в несколько раз.
Вот, например, была задача — вывести поле sum со знаком «-», если type=1 и со знаком «+», если type=0.
Пользователь предложил такое решение:
SELECT id, sum FROM transactions t WHERE type = 0 UNION ALL SELECT id, -sum FROM transactions t WHERE type = 1
В целом, не так плохо. Но это всего лишь промежуточный запрос, задача была намного масштабней и таких конструкций в итоге было наворочено очень много.
А вот то же самое с CASE:
SELECT id, CASE WHEN type = 0 THEN sum ELSE -sum END FROM transactions t
Согласитесь, получше?
Так более того, CASE можно использовать еще много для чего. Например, чтобы сделать из «длинной» таблицы «широкую».
А еще, кстати, COALESCE, который мы обсуждали выше — это просто «синтаксический сахар» и обертка вокруг CASE. Если интересно — мы подробно это описали в статье.
6. Лишние подзапросы
Из-за того, что многие пишут SQL-запросы также, как это «звучит» в их голове, получается нагромождение подзапросов.
Это проходит с опытом — начинаешь буквально «мыслить на SQL» и все становится ок. Но первое время появляются такие штуки:
SELECT id, LAG(neg) OVER(ORDER BY id) AS lg FROM ( SELECT id, sm, -sm AS neg FROM ( SELECT id, sum AS sm FROM transactions t ) t ) t1
И это еще не все — можно и побольше накрутить. Но зачем так, если можно так:
SELECT id, LAG(-sum) OVER(ORDER BY id) FROM transactions t
Совет: Если пока сложно, не надо сразу бросаться писать оптимизированными конструкциями. Напишите сначала, как сможете, а потом пытайтесь сократить.
Как говорил дядюшка Кнут:
Преждевременная оптимизация — корень всех зол
7. Неправильное использование оконных функций
Вообще говоря, оконные функции — довольно продвинутый инструмент. Считается, что им владеют специалисты уровня Middle и выше. Но по факту, их нужно знать всем — сейчас без них уже сложно жить (это чистое имхо).
И если базовые вещи по оконным функциям можно освоить довольно быстро, то всякая экзотика и нестандартное поведение осваивается, как правило, только на собственных шишках.
Одна из таких вещей — поведение оконной функции LAST_VALUE и прочих.
Например, когда мы пишем запрос:
WITH cte AS ( SELECT 'Marketing' AS department, 50 AS employees, 2018 AS year UNION SELECT 'Marketing' AS department, 10 AS employees, 2019 AS year union SELECT 'Sales' AS department, 35 AS employees, 2018 AS year UNION SELECT 'Sales' AS department, 25 AS employees, 2019 AS year ) SELECT c.*, LAST_VALUE(employees) OVER (PARTITION BY department ORDER BY year) AS emp FROM cte c
Мы ожидаем увидеть 2 раза по 10 для департамента Маркетинг и 2 раза по 25 для Продаж. Однако такой запрос дает иную картину:
Получается, что запрос тупо продублировал значения из столбца employees. Как так?
Лезем в документацию PostgreSQL и видим:
Заметьте, что функции first_value, last_value и nth_value рассматривают только строки в «рамке окна», которая по умолчанию содержит строки от начала раздела до последней родственной строки для текущей.
Ага, вот и ответ. То есть каждый раз у нас окно — это не весь набор строк, а только до текущей строки.
Получается, есть два способа вылечить такое поведение:
Вот, например, второй вариант:
WITH cte AS ( SELECT 'Marketing' AS department, 50 AS employees, 2018 AS year UNION SELECT 'Marketing' AS department, 10 AS employees, 2019 AS year union SELECT 'Sales' AS department, 35 AS employees, 2018 AS year UNION SELECT 'Sales' AS department, 25 AS employees, 2019 AS year ) SELECT c.*, LAST_VALUE(employees) OVER ( PARTITION BY department ORDER BY year ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING ) AS emp FROM cte c
Кстати, такую тему подняла наша подписчица в Телеграме под постом «7 самых важных оконных функций». Спасибо ей!
А вас рады будем видеть в числе подписчиков 🙂
Эпилог
Эти 7 ошибок — не единственные, которые часто встречаются среди новичков и даже профессионалов. У нас есть еще одна пачка тезисов по этому поводу — но это уже тема другой статьи.
Если вам есть что добавить — будем рады продолжить обсуждение в комментариях. Возможно, чей-то код станет лучше и чище в результате нашей беседы 🙂
Функция MySQL Coalesce() — Разделы по масштабированию
Обзор
MySQL функция Coalesce возвращает первое ненулевое значение из списка выражений. Он принимает список значений в качестве параметра, а затем оценивает этот список. Функция «coalesce» MySQL заменяет нулевые значения, представленные в списке, значением, определенным пользователем. Затем он начинает вычислять выражение. Эта оценка данного списка выполняется в определенной последовательности и всегда возвращает первое ненулевое значение.
Синтаксис функции MySQL Coalesce()
Ниже приведен синтаксис функции Coalesce MySQL:
Параметры функции MySQL Coalesce()
Функция Coalesce MySQL принимает одно (или более) значение в виде списка аргументов следующим образом:
- Эти значения могут иметь любой тип данных или могут быть нулевыми значениями.
- Затем эти значения обрабатываются как список, и MySQL-функция «coalesce» проходит по списку в определенном порядке.
Примечание : Чтобы значение было нулевым, оно должно быть указано явно. В отличие от других языков, SQL не обрабатывает пустые значения как значения NULL.
Возвращаемое значение функции MySQL Coalesce()
- Функция MySQL Coalesce проходит через значения, переданные в качестве параметров, и возвращает первое ненулевое значение .
- Функция MySQL объединения возвращает NULL , когда все значения, переданные в качестве параметров, равны нулю.
Как работает функция MySQL Coalesce()?
Как обсуждалось выше, функция объединения MySQL используется для возврата первого ненулевого значения из списка выражений. MySQL-функция «coalesce» принимает последовательность значений, которые могут относиться как к одному, так и к разным типам данных.
Примечание: Функция «coalesce» в MySQL — это синтаксическая короткая форма выражения case в MySQL. Он оценивает каждый аргумент в списке как случай и возвращает первый случай, который не равен нулю.
Например, предположим, что у нас есть следующий список, в котором мы хотим найти первое ненулевое значение:
Теперь, когда приведенный выше список передается функции объединение(), она начнет оценивать список слева. Во-первых, он проверит, является ли первое значение нулевым. Поскольку первое значение равно null, оно перейдет к следующему значению. Опять же, он проверит, является ли второе значение нулевым. Поскольку второе значение 3456 не является нулевым, поиск первого ненулевого значения прервется и будет возвращено 3465.
Примеры
Пример 1: Использование функции объединения MySQL со всеми числовыми параметрами
В этом примере мы будем использовать функцию объединения MySQL, чтобы найти первое ненулевое значение из последовательности переданных числовых параметров.
Код :
Вывод :
Пояснение к примеру :
В приведенном выше примере мы передали список null, null, 140, 99, null , и 1010 для нашей функции объединения MySQL . Затем эта функция проходит слева направо по каждому переданному значению и проверяет, является ли оно нулевым. Когда функция объединения MySQL встречает 140, проверка нуля завершится ошибкой, поэтому она вернет 140.
Пример 2: Использование функции объединения MySQL со всеми строковыми параметрами
В этом примере мы будем использовать функцию объединения MySQL, чтобы найти первое ненулевое значение из переданной последовательности строковых параметров.
Код :
Вывод :
Пояснение к примеру :
В приведенном выше примере мы передали список null, ‘Peter’, null, ‘J on’, ‘Брюс’, ноль к нашей функции объединения MySQL. Затем эта функция проходит слева направо по каждому переданному значению и проверяет, является ли оно нулевым. Когда функция объединения MySQL встречает «Питер», проверка нуля завершится ошибкой, поэтому она вернет «Питер».
Пример 3: Использование функции объединения MySQL со смешанными параметрами
В этом примере мы будем использовать функцию объединения MySQL, чтобы найти первое ненулевое значение из переданной последовательности смешанных параметров.
Код :
Вывод :
Пояснение к примеру :
В приведенном выше примере мы передали список null, null, 100, ‘Jon’ , «Брюс», ноль, 9090 к нашей функции объединения MySQL. Затем эта функция проходит слева направо по каждому переданному значению и проверяет, является ли оно нулевым. Когда функция объединения MySQL встречает 100, проверка на ноль завершится ошибкой, поэтому она вернет 100.
Пример 4: Использование функции объединения MySQL со всеми нулевыми параметрами
В этом примере мы будем использовать функцию объединения MySQL, чтобы найти первое ненулевое значение из последовательности всех переданных нулевых параметров.
Код :
Вывод :
Пояснение к примеру :
В приведенном выше примере мы передали список null, null, null нашей функции объединения MySQL. Затем эта функция проходит слева направо по каждому переданному значению и проверяет, является ли оно нулевым. Поскольку у него нет ненулевого значения, он вернет NULL.
Заключение
- MySQL функция объединения используется для возврата первого ненулевого значения из списка выражений.
- В качестве параметров принимает одно (или более) значение.
- Значения могут быть одного или разных типов данных.
- Функция «coalesce» MySQL возвращает нулевое значение, если в качестве аргумента не передается ненулевое значение.
- Функция объединения MySQL эквивалентна оператору case в MySQL.
См. также
- Не нуль в SQL
MCQ
Что функция объединения MySQL возвращает ?
- а) Первое нулевое значение.
- b) Первое ненулевое значение.
- c) Последнее ненулевое значение.
- d) Последнее нулевое значение.
Ответ : б
Что произойдет, если в функцию объединения MySQL не будет передано ненулевое значение ?
- а) Отображает ошибку.
- б) Возвращает 0.
- c) Возвращается ноль.
- г) Возвращает все значения, переданные в качестве параметров.
Ответ : с
Что из следующего неверно для функции объединения MySQL ?
- а) Это краткая синтаксическая форма выражения case в MySQL.
- б) В качестве параметра принимает список значений.
- c) Может принимать параметры разных типов данных.
- г) Возвращает общее количество ненулевых значений в списке.
Ответ : д
Преобразование значения NULL в MySQL с помощью COALESCE() — средний репост
Помнить о значениях NULL — хорошая практика. NULL s могут ускользнуть от вас и дать вам чертовски много времени (особенно в вычислениях), если вы не будете осторожны . В этом посте мы увидим примеры преобразования NULL с функцией MySQL COALESCE() .
Ознакомьтесь со статьями премиум-класса, подробными руководствами, обучающими видеороликами и многим другим, присоединившись к «Уровень обучения MySQL» членство. У вас есть доступ к эксклюзивному контенту, неопубликованному где-либо еще с этим членством. Поскольку новый контент регулярно добавляется, продолжайте изучать MySQL на любом уровне.
Изучайте MySQL!
Изображение Герда Альтманна из Pixabay
Информационный бюллетень для разработчиков PHP и MySQL
Получите копию моей электронной книги «10 советов по MySQL для всех» , абсолютно бесплатно при подписке к Информационный бюллетень OpenLampTech .
MySQL Функция COALESCE() принимает несколько аргументов и возвращает первое значение, отличное от NULL . Если нет не- NULL s, COALESCE() возвращает NULL .
Получайте индивидуальные статьи с помощью Refind каждый день в свой почтовый ящик. Refind — часть моей ежедневной привычки к чтению. Сделайте его частью своего, используя мою реферальную ссылку. Без каких-либо дополнительных затрат для вас я буду иметь право на премиум-подписку с большим количеством регистраций по моей ссылке. “ Суть Интернета, каждое утро в вашем почтовом ящике. Подпишитесь бесплатно »
Прочтите весь пост, Преобразование значений NULL с помощью функции MySQL COALESCE, чтобы узнать, как заменить значения NULL чем-то более значимым в результатах запроса.
Самореклама:
Если вам нравится содержание, написанное здесь, во что бы то ни стало, поделитесь этим блогом и вашими любимыми сообщениями с другими, кому они тоже могут быть полезны или понравиться. Поскольку кофе — мой любимый напиток, вы даже можете купить мне его, если хотите!
Продемонстрируйте свою поддержку моего блога и контента, бросив любую лишнюю мелочь, которая у вас есть, в мою банку для чаевых.
Баночка для чаевых
Вы являетесь пользователем Medium? Если это так, получайте уведомление по электронной почте каждый раз, когда я публикую сообщение в блоге, если вы предпочитаете платформу Medium. Не член? Не беспокойся! Воспользуйтесь моей ссылкой для регистрации (я получу комиссию без дополнительных затрат для вас) и присоединяйтесь. Мне очень нравится читать весь этот замечательный контент, и я знаю, что вам тоже понравится!!!
Аналогичное чтение
Если вам понравилась эта статья, вам также может понравиться любой из этих постов. Поделитесь ими вместе. Спасибо. путешествие разработчика, где я разделяю большую часть своих целей и приверженности обучению кодировать. Прочтите это интервью.
Спасибо, что прочитали этот пост. Пожалуйста, поделитесь им с кем-то еще, кому это тоже понравится.
Джош Отвелл хочет развиваться как PHP-разработчик, эксперт по SQL и технический блоггер/писатель.
Отказ от ответственности: большинство примеров в этом посте выполняются в среде рабочей станции для персональной разработки/обучения, и не следует считать производственным качеством или готовым . Ваши конкретные цели и потребности могут отличаться. Как всегда, только потому, что вы можете что-то сделать, не означает, что вы должны . Мои мнения являются моими собственными.
Чем еще я могу помочь
- LoopGenius поможет вам найти клиентов, распространить информацию о вашей подработке и превратить вашу идею в веб-сайт. Используйте код купона: KZGZ3WSP , когда вы зарегистрируетесь сегодня и получите скидку 10%!
- Узнайте о Google Analytics с помощью этого курса, подготовленного ребятами из The Content Technologist.
- Нужен хостинг для вашего следующего веб-приложения или сайта WordPress? Я настоятельно рекомендую Hostinger и использовать их для размещения моего нишевого сайта по ловле окуня . Сервис не имеет себе равных.
- 🔒 5 истин, которые я осознал как разработчик-самоучка
- Мобильные обои, цифровые загрузки, фотографии, услуги по разработке и контент — все в одном Kofi Shop Страница . Найдите свою следующую цифровую покупку сегодня!
Раскрытие информации : Некоторые из ссылок на услуги и продукты в этом сообщении в блоге являются партнерскими ссылками. Без каких-либо дополнительных затрат для вас, если вы совершите покупку, нажав на один из них, я получу комиссию.
Информационный бюллетень для разработчиков PHP и MySQL
Получите копию моей электронной книги «10 советов по MySQL для всех» , абсолютно бесплатно при подписке на OpenLampTech 9021 6 бюллетень.