我使用的是 Microsoft SQL Azure (RTM) - 12.0.2000.8,我有一个表,其中包含提供商收到评级的多个日期。
我需要为每个提供商自 4 月 22 日以来的每个月输出一行,并包含该日期提供商的最新评级。
这是我必须使用的评级表:
日期 | 提供商 | 评分 |
---|---|---|
2022-04-30 | A | 1 |
2022-05-31 | B | 2 |
2022-07-31 | A | 5 |
我尝试使用 LAST_VALUE 函数来完成此操作,但它并没有填充此内容。
WITH CTE_Dates AS ( --create date table as ratings table does not have record for every month
SELECT
EOMONTH([Date], 0) AS [ReportingDate]
FROM [tbl_Dates]
WHERE [Date] >= '2022-04-01'
AND [DATE] <= '2022-08-31'
GROUP BY EOMONTH([Date], 0)
)
,
CTE_Ratings AS (
SELECT
[ReportingDate]
,[Provider]
,[Rating]
FROM Ratings
)
SELECT
CTE_Dates.[ReportingDate]
,[Provider]
,[Rating]
,LAST_VALUE([Rating]) OVER (PARTITION BY CTE_Dates.[ReportingDate], [Provider] ORDER BY CTE_Dates.[ReportingDate]
) AS latest_rating
FROM CTE_Dates
LEFT OUTER JOIN CTE_Ratings
ON CTE_Dates.[ReportingDate] = CTE_Ratings.[ReportingDate]
我的输出:
日期 | 提供商 | 评分 | 最新评级 |
---|---|---|---|
2022-04-30 | A | 1 | 1 |
2022-05-31 | 空 | 空 | 空 |
2022-06-30 | 空 | 空 | 空 |
2022-07-31 | A | 5 | 5 |
2022-08-31 | 空 | 空 | 空 |
2022-04-30 | 空 | 空 | 空 |
2022-05-31 | B | 2 | 2 |
2022-06-30 | 空 | 空 | 空 |
2022-07-31 | 空 | 空 | 空 |
2022-08-31 | 空 | 空 | 空 |
所需输出:
日期 | 提供商 | 评分 | 最新评级 |
---|---|---|---|
2022-04-30 | A | 1 | 1 |
2022-05-31 | A | 空 | 1 |
2022-06-30 | A | 空 | 1 |
2022-07-31 | A | 5 | 4 |
2022-08-31 | A | 空 | 5 |
2022-04-30 | B | 空 | 空 |
2022-05-31 | B | 2 | 2 |
2022-06-30 | B | 空 | 2 |
2022-07-31 | B | 空 | 2 |
2022-08-31 | B | 空 | 2 |
如果我们使用您提供给我们的样本数据,您的查询和您所说的得到的结果肯定不一样。因此,我使用您的数据定义了一个
#Ratings
表并由自己的日历表使用。
首先,我得到每个月的最后一天,这可以通过
EOMONTH
实现,但我没有从日历表中得到每个日期;第一天就足够了,可以通过查询“日历日”列轻松返回。
然后,看来我们需要每个日期和提供者一个不同的行,这是您的查询所缺少的。这可以通过日期 CTE 和
CROSS JOIN
表之间的 Ratings
来完成,并获取两列组合的 DISTINCT
值。然而,理想情况下,您会 CROSS JOIN
到 Provider
表,以消除 DISTINCT
。
尽管样本数据表明并非如此,但我假设
Rating
的值不 总是增加。如果是,那么窗口 MAX
就可以工作。然而,假设不是,那么您在这里缺少的是 IGNORE NULLS
运算符。如果添加它,您将获得所需的结果,因为获取 最后一个值时会忽略
NULLs
值。
CREATE TABLE #Ratings (Date date,
Provider char(1),
Rating int);
GO
INSERT INTO #Ratings (Date,
Provider,
Rating)
VALUES('2022-04-30','A',1),
('2022-05-31','B',2),
('2022-07-31','A',5);
GO
WITH Dates AS(
SELECT EOMONTH(CalendarDate) AS [ReportingDate]
FROM tbl.Calendar
WHERE CalendarDate >= '2022-04-01'
AND CalendarDate <= '2022-08-31'
AND CalendarDay = 1),
RatingDates AS(
SELECT DISTINCT
R.Provider,
D.ReportingDate
FROM #Ratings R
CROSS JOIN Dates D)
SELECT RD.[ReportingDate],
RD.[Provider],
LAST_VALUE(R.Rating) IGNORE NULLS OVER (PARTITION BY RD.Provider ORDER BY RD.ReportingDate) AS Rating
FROM RatingDates RD
LEFT OUTER JOIN #Ratings R ON RD.[ReportingDate] = R.Date
AND RD.Provider = R.Provider
ORDER BY RD.Provider,
RD.ReportingDate;
GO
DROP TABLE #Ratings