Найти в Дзене

PG: Сортировка по самому позднему заполненному полю из двух (d_last_login и d_active)

Для сортировки по самому позднему значению между двумя полями даты, где одно или оба могут быть NULL, в PostgreSQL есть несколько эффективных способов: SELECT * FROM your_table ORDER BY GREATEST( COALESCE(d_last_login, '1970-01-01'::timestamp), COALESCE(d_active, '1970-01-01'::timestamp) ) DESC; SELECT * FROM your_table ORDER BY CASE WHEN d_last_login IS NOT NULL AND d_active IS NOT NULL THEN GREATEST(d_last_login, d_active) WHEN d_last_login IS NOT NULL THEN d_last_login WHEN d_active IS NOT NULL THEN d_active ELSE NULL END DESC NULLS LAST; SELECT * FROM your_table ORDER BY ( SELECT MAX(dt) FROM (VALUES (d_last_login), (d_active)) AS dates(dt) WHERE dt IS NOT NULL ) DESC NULLS LAST; SELECT * FROM your_table ORDER BY ( SELECT MAX(date) FROM ( SELECT d_last_login AS date WHERE d_last_login IS NOT NULL UNION ALL SELECT d_active AS date WHERE d_active IS NOT NULL ) AS dates ) DESC NULLS LAST; Для большинства случаев я рекомендую вариант 3 (для PostgreSQL 9.5+) или вариант 2 (для более ст
Оглавление

Для сортировки по самому позднему значению между двумя полями даты, где одно или оба могут быть NULL, в PostgreSQL есть несколько эффективных способов:

1. Использование COALESCE с GREATEST (простой способ)

SELECT *
FROM your_table
ORDER BY GREATEST(
COALESCE(d_last_login, '1970-01-01'::timestamp),
COALESCE(d_active, '1970-01-01'::timestamp)
) DESC;

2. Точная обработка NULL значений

SELECT *
FROM your_table
ORDER BY CASE
WHEN d_last_login IS NOT NULL AND d_active IS NOT NULL
THEN GREATEST(d_last_login, d_active)
WHEN d_last_login IS NOT NULL THEN d_last_login
WHEN d_active IS NOT NULL THEN d_active
ELSE NULL
END DESC NULLS LAST;

3. Современный способ (PostgreSQL 9.5+)

SELECT *
FROM your_table
ORDER BY (
SELECT MAX(dt)
FROM (VALUES (d_last_login), (d_active)) AS dates(dt)
WHERE dt IS NOT NULL
) DESC NULLS LAST;

4. Альтернатива с UNION ALL

SELECT *
FROM your_table
ORDER BY (
SELECT MAX(date)
FROM (
SELECT d_last_login AS date WHERE d_last_login IS NOT NULL
UNION ALL
SELECT d_active AS date WHERE d_active IS NOT NULL
) AS dates
) DESC NULLS LAST;

Особенности каждого подхода:

  1. Первый вариант самый простой, но использует фиктивную дату для NULL значений
  2. Второй вариант точнее обрабатывает NULL, но длиннее в написании
  3. Третий вариант наиболее лаконичный для современных версий PostgreSQL
  4. Четвертый вариант работает во всех версиях, но менее эффективен для больших таблиц

Для большинства случаев я рекомендую вариант 3 (для PostgreSQL 9.5+) или вариант 2 (для более старых версий).