让我们得到以下数据
CREATE TABLE [dbo].[LogTable] ([DateSent] [datetime] NULL)
GO
CREATE CLUSTERED INDEX [IX_LogTable_DateSent] ON [dbo].[LogTable] ([DateSent] DESC)
GO
INSERT INTO [LogTable]
SELECT TOP 500000 NULL, DATEADD(day, ( ABS(CHECKSUM(NEWID())) % 65530 ), 0)
FROM sys.sysobjects
CROSS JOIN sys.all_columns
我想在DateSent
找到每年的第二个和第三个最低值。 Oracle为此提供了NTH_VALUE
函数,但是,SQL Server中没有这样的功能。我创建了以下查询
SELECT YEAR(datesent),
(
SELECT datesent
FROM
(
SELECT datesent, ROW_NUMBER() OVER (ORDER BY datesent) r
FROM logtable
WHERE YEAR(datesent) = YEAR(lt.datesent)
) logtable_ranked
WHERE logtable_ranked.r = 2
) second_lowest_in_year,
(
SELECT datesent
FROM
(
SELECT datesent, ROW_NUMBER() OVER (ORDER BY datesent) r
FROM logtable
WHERE YEAR(datesent) = YEAR(lt.datesent)
) logtable_ranked
WHERE logtable_ranked.r = 3
) thirt_lowest_in_year
FROM logtable lt
GROUP BY YEAR(datesent)
返回正确的结果,但我的服务器上的CPU时间超过7秒。此外,该解决方案的时间随着我需要的许多NTH值线性增长。是否有更好(更快,也许更优雅)的方式来计算SQL Server中的NTH_VALUE?
答案 0 :(得分:2)
使用row_number()
和条件聚合:
SELECT YEAR(datesent),
MAX(CASE WHEN seqnum = 1 THEN datesent END) AS datesent_1,
MAX(CASE WHEN seqnum = 2 THEN datesent END) AS datesent_2,
MAX(CASE WHEN seqnum = 3 THEN datesent END) AS datesent_3
FROM (SELECT datesent,
ROW_NUMBER() OVER (PARTITION BY YEAR(datesent) ORDER BY datesent) AS seqnum
FROM LogTable lt
) lt
GROUP BY YEAR(datesent)
ORDER BY YEAR(datesent);