#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
Предложение уменьшает количество повторяющихся строк. Это сокращение может быть выполнено двумя способами:
- использование has table — hashing не сохраняет порядок
- использование сортировки и удаление равных следующих строк — эта сортировка нарушает исходный порядок.
Если вы хотите заблокировать это поведение, используйте UNION ALL
предложение, которое не уменьшает количество избыточных строк (дубликатов).
Ответ №3:
order by
не является частью select
. select
выдает таблицу, представляющую собой набор, в котором нет порядка. Вы можете сделать order by
в конце и, по-видимому, также в объединениях, но, например, вы не можете присоединиться к упорядоченному набору (по крайней мере, не в sybase).