Запрос Psql: Объединение не сохраняет порядок строк, поступающих из cte

#sql #postgresql #sql-order-by #union #common-table-expression

#sql #postgresql #sql-order-by #объединение #common-table-expression

Вопрос:

У меня есть этот запрос:

 with cte1 as (select salary from employees order by salary desc), cte2 as (select 850) select * from cte1 union select * from cte2;
  

cte1 упорядочен по столбцу зарплаты, а cte2 — нет. Я хочу, чтобы результаты cte2 добавлялись к результатам cte1, сохраняя порядок результатов из cte1. Но этого не происходит.

Если я выполняю приведенный выше запрос без объединения со вторым cte, результаты отображаются в ожидаемом порядке, но порядок нарушается при наличии объединения.

Запрос без объединения:

 with cte1 as (select salary from employees order by salary desc), cte2 as (select 850) select * from cte1;
 salary 
--------
   1000
    900
    800
    700
    600
    500
  

С объединением:

 with cte1 as (select salary from employees order by salary desc), cte2 as (select 850) select * from cte1 union select * from cte2;
 salary 
--------
    850
    800
    700
    900
    500
    600
   1000
  

Кто-нибудь, пожалуйста, может объяснить, почему это происходит?

Комментарии:

1. Общее правило таково: если вам нужен определенный порядок, используйте ORDER BY .

Ответ №1:

Из документации ясно, что union это не гарантирует порядок строк:

UNION эффективно добавляет результат query2 к результату query1 (хотя нет гарантии, что это тот порядок, в котором строки фактически возвращаются).

Если вы хотите, чтобы результаты были упорядочены, затем используйте order by во внешнем запросе; для вашего варианта использования это требует отслеживания того, из какого cte берется каждая строка

 with 
    cte1 (salary, which) as (select salary, 1 from employees), 
    cte2 (salary, which) as (select 850, 2) 
select salary from cte1 
union all
select salary from cte2
order by which, salary desc;
  

Обратите внимание, что я изменил union на union all ; не похоже, что вы хотите дедуплицировать строки (что делает первый), поэтому последний достаточно хорош (и более эффективен).

Ответ №2:

UNION Предложение уменьшает количество повторяющихся строк. Это сокращение может быть выполнено двумя способами:

  1. использование has table — hashing не сохраняет порядок
  2. использование сортировки и удаление равных следующих строк — эта сортировка нарушает исходный порядок.

Если вы хотите заблокировать это поведение, используйте UNION ALL предложение, которое не уменьшает количество избыточных строк (дубликатов).

Ответ №3:

order by не является частью select . select выдает таблицу, представляющую собой набор, в котором нет порядка. Вы можете сделать order by в конце и, по-видимому, также в объединениях, но, например, вы не можете присоединиться к упорядоченному набору (по крайней мере, не в sybase).