与联盟的行为有奇怪的顺序

use*_*eve 2 sql t-sql sql-server

有人可以向我解释这里发生了什么.行为不像我期望的那样:

select category,timefield from test where category='A'
union
select top 10 category,timefield from test where category='B' order by timefield desc
Run Code Online (Sandbox Code Playgroud)

我想要的是A类的所有行,只有B类中最近的10行.
执行时,结果实际上是:所有类别A(按时间字段降序排序)+ 类别B 的 10行(按时间字段降序排序) )

更奇怪的是,如果我们将整个语句放在子查询中,我希望行为保持不变并像之前一样进行评估,但它不是:

select * from (
    select category,timefield from test where category='A'
    union
    select top 10 category,timefield from test where category='B' order by timefield desc
) subq
Run Code Online (Sandbox Code Playgroud)

这将返回所有类别A(按升序排列)+最近的10个类别B(按降序排列). 这正是我想要的.

为什么第一个语句不能产生我所期望的,为什么第二个语句表现得非常不同?

(这是SQL Server 2008)

Gor*_*off 5

您需要在第一个查询中使用括号,因为order by它应用于结果union.它被解释为:

(select category,timefield from test where category='A'
 union
 select top 10 category,timefield from test where category='B'
)
order by timefield desc
Run Code Online (Sandbox Code Playgroud)

(我不是说这是有效的语法.)

而你想要的是:

(select category, timefield from test where category='A')
union
(select top 10 category, timefield from test where category='B' order by timefield desc)
Run Code Online (Sandbox Code Playgroud)

请注意,union将删除重复项.如果您不想要这个额外的开销,请union all改用.

至于为什么它作为子查询工作,我的猜测是巧合.SQL Server不会保证在top没有使用时返回结果order by- 或者甚至从一次调用到下一次调用时结果是一致的.有时它实际上可能会做你想要的.