SQL:在使用Order By的UNION查询中使用Top 1

时间:2009-05-09 06:05:59

标签: sql-server sql-order-by union

我有一张表格如下

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

我不清楚为什么会这样?有什么建议吗?

4 个答案:

答案 0 :(得分:26)

它的工作原理如下:

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'

答案 1 :(得分:8)

忽略了作为联合一部分的select语句中的Order By。因此,您的TOP 1正在选择一些仲裁记录(可能是该表的聚簇键的第一条记录)。

答案 2 :(得分:3)

与联盟一起使用时,排序依据无效...

我使用Common Table Expression和一些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 ..

然后在查询的union部分..

在顶部,我们从“过去”列表(cur = 0)和“过去”列表中的第一个条目获得排名和日期..(sort = 1)..将返回1记录(如果搜索日期之前没有记录,则为0)..

然后我们将其与“当前”列表中的所有记录(cur = 1)联合起来

然后最后..我们取得UNION的结果..并在生效日期之前命令我们提供所有当前记录,以及“最新”以前的记录。

答案 3 :(得分:1)

我相信上述查询不包括05/01/2009使用&lt;和&gt;而不是&lt; =和&gt; =。