Psql查询:联合不保留来自cte的行的顺序

问题描述

我有这个查询

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

任何人都可以解释为什么会这样吗?

解决方法

documentation很清楚,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;似乎您不想对行进行重复数据删除(前者确实如此),所以后者足够好(而且效率更高)。

,

order by不是select的一部分。 select给出一个表,该表是一个集合,没有顺序。您可以在末尾order by进行操作,显然也可以在并集中进行操作,但是例如,您不能与有序集(至少不是在sybase中)连接。

,

UNION子句减少重复的行。这种减少可以通过两种技术来完成:

  1. 使用has表-哈希不能保留顺序
  2. 使用排序并删除随后的相等行-这种排序会破坏原始顺序。

如果要阻止此行为,请使用UNION ALL子句,这不会减少多余的行(重复)。