Доброго дня! Нужна чуть больше информации, чтобы точно сказать, почему у вас “странное” поведение (какая СУБД, сам запрос, пример данных и ожидаемый/фактический результат). Ниже — перечень типичных причин и как их проверять/устранять: возможно, одна из них и есть ваша проблема.
Что важно проверить (и что чаще всего вызывает сюрпризы)
1) Типы данных и приоритет типов
- COALESCE возвращает значение одного типа, и СУБД приводит аргументы к общему типу по правилам приведения/приоритетов. Из‑за этого возможны ошибки или неявные приведения.
- Пример (SQL Server): SELECT COALESCE('abc', 1) приведёт к ошибке «conversion failed», потому что СУБД попытается привести 'abc' к INT (int имеет более высокий приоритет).
- Решение: явно привести тип нужным CAST/CONVERT, например COALESCE(CAST(col AS varchar(100)), other_col).
2) NULL vs пустая строка / ноль
- В разных СУБД '' не равен NULL. Если ожидаете, что пустая строка считается «нет значения», используйте NULLIF или CHECK (например NULLIF(col,'') или CASE WHEN col = '' THEN NULL ELSE col END).
- Для чисел: 0 ≠ NULL. Не путайте COALESCE(col,0) (подставит 0 при NULL) и SUM(COALESCE(col,0)) (каждый NULL превратится в 0) vs COALESCE(SUM(col),0) (подставит 0 если результат агрегата NULL).
3) Короткое/ленивое вычисление (short‑circuit) и побочные эффекты
- В некоторых случаях выражения в COALESCE могут быть приведены/оценены даже если первый аргумент не NULL (например, из‑за приведения типов или реализации). Это может привести к ошибкам (деление на ноль, обращение к несуществующему столбцу в подзапросе и т.п.).
- Надежный способ избежать вычисления опасного выражения — использовать CASE WHEN, например:
CASE WHEN denom = 0 THEN NULL ELSE numerator/denom END
CASE гарантированно не вычисляет ветку, если условие её исключает (это стандартизированное поведение и безопаснее в подобных случаях).
4) COALESCE vs ISNULL/IFNULL (диалект)
- В SQL Server ISNULL(a,b) возвращает тип первого аргумента (и длину varchar первого аргумента), COALESCE использует правила совместимости типов/приоритета — поведение отличается.
- В MySQL аналог — IFNULL, в Postgres — COALESCE (но правила типов у Postgres строже: типы должны быть совместимы или явно указаны).
5) Колляция/кодировка строк
- Если аргументы строковых типов с различными коллациями — может быть ошибка или неожиданное приведение. Явно указывайте COLLATE или приводите в один тип/коллацию.
6) COALESCE с подзапросами/функциями
- Если аргументы — подзапросы, они могут выполняться/пытаться выполниться все (в зависимости от СУБД/плана), что даст неожиданный эффект. Лучше вынести подзапросы в JOIN/OUTER APPLY или использовать CASE.
Как отладить
- Покажите типы колонок: в Postgres — pg_typeof(col), в SQL Server — SQL_VARIANT_PROPERTY или INFORMATION_SCHEMA.COLUMNS.
- Попробуйте отдельно выполнить каждое выражение.
- Явно CAST/CONVERT каждый аргумент в ожидаемый тип и проверьте результат.
- Замените COALESCE на CASE WHEN для теста (чтобы проверить проблемы с вычислением аргументов).
Короткие примеры
- Проблема с типами (SQL Server):
SELECT COALESCE('123', 456); -- вернёт 123 как INT (строка приведена к INT)
SELECT COALESCE('abc', 1); -- ошибка: conversion failed
Исправление:
SELECT COALESCE(CAST(col1 AS varchar(100)), CAST(col2 AS varchar(100)));
- Избежание деления на ноль:
-- плохой вариант (может быть ошибка, если 1/0 вычислится):
SELECT COALESCE(NULL, 1/0);
-- безопасный:
SELECT CASE WHEN denom = 0 THEN NULL ELSE numerator/denom END;
Что мне нужно от вас, чтобы помочь точнее
- СУБД (Postgres, SQL Server, MySQL, Oracle и т. п.)
- Сам SQL‑запрос (или упрощённый пример)
- Пример(ы) исходных данных и ожидаемый/фактический результат
- Любые ошибки, которые СУБД выводит
Пришлите эти данные — проанализирую и подскажу конкретное решение.