Задать вопрос
@budzin

Странное поведение COALESCE в SQL запросе?

Пишу отчёт для того, чтобы учитывать количество дней, проведенных абонентом на тарифе за прошлый месяц.
Явно задаю даты во временной таблице и в RAW_DATA вызываю функцию COALESCE. В итоге в некоторых
столбцах появляется NULL. Пробовал приводить всё к одному типу данных - разницы нет.
С учётом того, что одни данные точно ненулевые – никакого NULL быть не может.

with
  report_period as (
    select
      DATE(DATE_FORMAT(DATE_SUB(NOW(), INTERVAL 1 MONTH), '%Y-%m-01')) as start_report_date,
      DATE(LAST_DAY(DATE_SUB(NOW(), INTERVAL 1 MONTH))) as end_report_date
),
  raw_data as (
    select
      t.vg_id, t.tar_id_old, t.tar_id_new, t.rasp_time,
      rp.start_report_date, rp.end_report_date,
      COALESCE(LAG(t.rasp_time) OVER(PARTITION BY t.vg_id ORDER BY t.rasp_time), rp.start_report_date) as prev_rasp_time,
      DATE(ag.date) as ag_date,
      DAY(ag.date) as agrm_day
    from tarifs_history t
    cross join report_period rp
    inner join vgroups v on v.vg_id = t.vg_id
    inner join agreements ag on ag.agrm_id = v.agrm_id
    where t.rasp_time
      between rp.start_report_date and rp.end_report_date
    order by t.vg_id desc, t.rasp_time
)
select
  vg_id, tar_id_old, tar_id_new, rasp_time, prev_rasp_time, start_report_date,
  DATEDIFF(rasp_time, prev_rasp_time) as active_days
from raw_data


Результат.
vg_id - tar_id_old - tar_id_new - rasp_time - prev_rasp_time - start_report_date - active_days
65660 - NULL - 267 - 2026-04-28 00:00:00.000000 - 2026-04-01 00:00:00.000000 - 2026-04-01 - 27
65659 - NULL - 267 - 2026-04-28 00:00:00.000000 - 2026-04-01 00:00:00.000000 - 2026-04-01 - 27
65658 - NULL - 110 - 2026-04-27 00:00:00.000000 - NULL - 2026-04-01 - NULL
  • Вопрос задан
  • 77 просмотров
Подписаться 1 Простой 2 комментария
Помогут разобраться в теме Все курсы
  • Stepik
    PRO C#. Базы данных
    2 месяца
    Далее
  • Академия Эдюсон
    Python-разработчик + ИИ
    9 месяцев
    Далее
  • ProductStar × РБК
    Профессия: Java-разработчик + ИИ
    9 месяцев
    Далее
Решения вопроса 1
opium
@opium
Просто люблю качественно работать
тут MySQL кривит на связке CTE + оконная функция + COALESCE — оптимизатор скорее всего объединяет CTE в основной запрос так, что rp.start_report_date оказывается NULL внутри COALESCE.

Чище всего — используй третий аргумент LAG вместо обёртки в COALESCE:
lag(t.rasp_time, 1, rp.start_report_date) over(partition by t.vg_id order by t.rasp_time) as prev_rasp_time


Если не поможет — разнеси по уровням: вычисли LAG в raw_data как отдельный столбец lag_rasp_time, COALESCE уже в следующем SELECT:
coalesce(lag_rasp_time, start_report_date) as prev_rasp_time


Можно ещё попробовать хинт NO_MERGE для report_period — Akina в комментарии намекнул правильно.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы