SQL:在 UNION 查询中使用 Top 1 和 Order By
Posted
技术标签:
【中文标题】SQL:在 UNION 查询中使用 Top 1 和 Order By【英文标题】:SQL: Using Top 1 in UNION query with Order By 【发布时间】:2009-05-09 06:05:59 【问题描述】:我有一张如下表
Rate Effective_Date
---- --------------
5.6 02/02/2009
5.8 05/01/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
我应该找到对当前日期及其之后有效的所有费率。所以要获得当前的有效利率,我使用
SELECT TOP 1 * from table
where effective_date < '05/05/2009'
order by effective date desc
查询当前日期之后的费率
SELECT * from table
where effective_date > '05/05/2009'
为了结合这两个结果,我使用联合作为
SELECT TOP 1 * from table
where effective_date < '05/05/2009'
order by effective date desc
UNION
SELECT * from table
where effective_date > '05/05/2009'
预期的结果是
Rate Effective Date
---- --------------
5.8 05/01/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
但我得到的实际结果是
Rate Effective Date
---- --------------
5.6 02/02/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
我不知道为什么会发生这种情况?有什么建议吗?
【问题讨论】:
我不确定您的“预期”结果实际上是您应该期待的结果。. 2009 年 3 月 15 日是您搜索前的“倒数第二个”“最新的上一个”记录“2009 年 5 月 5 日”的日期.. 您应该只在预期结果集中获得 3 条记录。 【参考方案1】:它是这样工作的:
select *
from (
select top 1 *
from table
where effective_date <= '05/05/2009'
order by effective_date desc
) as current_rate
union all
select *
from table
where effective_date > '05/05/2009'
【讨论】:
这是否解决了 Union 查询中不尊重“top x”的问题? (我认为 itr 在 MSSS 中有但没有玩过) 是的,您的答案的编辑版本确实有效(将按查询的顺序包装在联合的非按查询中)。和猫一样,有十几种不同的方法可以给它们剥皮。我验证了您的查询以返回与我相同的结果。你的方法非常适合快速而肮脏的“立即获取数据”情况......我喜欢我描述的 CTE 方法,因为一旦它被写入,你就可以对数据做任何你想做的事情。 (即,给我第二个最前的费率 [但不是最前的] 和所有“当前”费率) 当我需要使用TOP并遇到“UNION ate my ORDER BY”问题时,我也更喜欢使用派生表方法。 FWIW 这部分对我运行 MS SQL 2019 有效。我必须将两个 SELECT 都放入子查询中,然后将两者合并。 SQL 2019 的播放方式不同,或者因为我的两个查询都是 TOP(10)..ORDER BY 查询。【参考方案2】:作为联合的一部分的 select 语句中的 Order By 将被忽略。因此,您的 TOP 1 正在选择一些任意记录(可能是表的聚集键的第一条记录)。
【讨论】:
说得好。我以前遇到过这个确切的问题。【参考方案3】:与 Union 一起使用时,Order By 无效...
我使用公用表表达式和一些 Rank 和 Case 语句技巧处理了一个快速而肮脏的东西,以获得您正在寻找的结果..
WITH CTE_RATES ( RATE, EFFECTIVE_DATE, CUR, SORT )
AS (
SELECT
Rate,
Effective_date,
CASE WHEN Effective_date > '5/5/2009' THEN 1
ELSE 0
END,
RANK() OVER (PARTITION BY
CASE WHEN EFFECTIVE_DATE > '5/5/2009' THEN 1
ELSE 0
END
ORDER BY EFFECTIVE_DATE DESC)
FROM TestTable
)
SELECT RATE, EFFECTIVE_DATE
FROM (
SELECT RATE, EFFECTIVE_DATE
FROM CTE_RATES
WHERE CUR = 0 AND SORT = 1
UNION ALL
SELECT RATE, EFFECTIVE_DATE
FROM CTE_RATES
WHERE CUR = 1
) AS QRY
ORDER BY EFFECTIVE_DATE
解释发生了什么...
CTE 定义查询返回的速率、日期、当前和排序标志...
CASE 将结果分为搜索日期之前的结果和搜索日期之后的结果。我们在联合中使用案例 (Cur) 的结果从分区列表中提取结果。 .
Rank() 函数然后通过根据 CASE 语句用于分隔列表的相同标准创建分区来对列表进行排序。然后我们以降序方式按生效日期排序。这将采用“过去”列表并使其成为最新的“过去”条目排名 1..
然后在查询的联合部分..
在顶部,我们从“过去”列表 (cur = 0) 和“过去”列表中的第一个条目中获取排名和日期.. (sort = 1).. 这将返回 1记录(如果没有搜索日期之前的记录,则为 0)..
然后我们将其与“当前”列表 (cur = 1) 中的所有记录合并
然后最后.. 我们采用 UNION 的结果.. 并在生效日期之前订购它,为我们提供所有当前记录以及“最新”的先前记录。
【讨论】:
【参考方案4】:我相信上述查询通过使用 而不是 = 排除了 05/01/2009。
【讨论】:
以上是关于SQL:在 UNION 查询中使用 Top 1 和 Order By的主要内容,如果未能解决你的问题,请参考以下文章
LINQ体验——LINQ to SQL语句之Union All/Union/Intersect和Top/Bottom和Paging和SqlMethods
在 SQL 查询中一起使用 union 和 count(*)