我有一些数据想要在分组变量(n
)中计算百分位(在Weekday
上)。我可以使用while循环来完成此操作,但是正在尝试使用CTE。当我尝试转换为CTE时,会得到:
PERCENTILE_DISC函数的输入参数必须为常量。
如何在递归CTE中使用窗口函数?
将伪造的数据集作为临时表
IF(OBJECT_ID('tempdb..##TEMP') IS NOT NULL) BEGIN DROP TABLE ##TEMP END
;WITH cte_numbers(n, weekday)
AS (
SELECT
0,
DATENAME(DW, 0)
UNION ALL
SELECT
n + 1,
DATENAME(DW, n + 1)
FROM
cte_numbers
WHERE n < 1000
)
SELECT weekday, n INTO ##Temp
FROM cte_numbers
OPTION (maxrecursion 1000)
-- SELECT * FROM ##TEMP
同时使用循环解决方案
DECLARE @PercentileLookup TABLE(
[Weekday] VARCHAR(250),
[Percentile] INT,
[n] INT
)
DECLARE @p INT;
SET @p=0;
WHILE @p < 101
BEGIN
INSERT INTO @PercentileLookup
SELECT DISTINCT
frm.[Weekday],
@p as Percentile,
PERCENTILE_DISC(CAST(@p AS FLOAT)/100) WITHIN GROUP (ORDER BY frm.[n]) OVER(PARTITION BY frm.[Weekday]) as n
FROM ##Temp as frm
SET @p = @p + 1;
END;
SELECT * FROM @PercentileLookup
ORDER BY Weekday, n, Percentile
尝试使用递归CTE和错误消息
WITH PercentileLookup(Weekday, Percentile, n) AS (
SELECT
frm.[Weekday],
0,
PERCENTILE_DISC(CAST(.0 AS FLOAT)/100) WITHIN GROUP (ORDER BY frm.[n]) OVER(PARTITION BY frm.[Weekday]) as n
FROM ##Temp as frm
UNION ALL
SELECT
frm.[Weekday],
Percentile + 1,
PERCENTILE_DISC(CAST(Percentile AS FLOAT)/100) WITHIN GROUP (ORDER BY frm.[n]) OVER(PARTITION BY frm.[Weekday]) as n
FROM PercentileLookup as pl
INNER JOIN ##Temp as frm ON frm.[Weekday] = pl.[Weekday]
WHERE Percentile <= 100
)
SELECT DISTINCT * FROM PercentileLookup
--Msg 8726, Level 16, State 1, Line 70
--Input parameter of PERCENTILE_DISC function must be a constant.
--Completion time: 2020-03-11T13:26:16.4701034-04:00
答案 0 :(得分:1)
您不能使用rCTE或Tally(更好的 )。如documentation所述(错误告诉您),第一个参数必须是 literal ;列的值不是文字,因此无法使用。
您可以使用动态语句来执行此操作,但这并不理想:
DECLARE @SQL nvarchar(MAX),
@CRLF nchar(2) = NCHAR(13) + NCHAR(10);
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT CONVERT(decimal(3,0),0) AS I
UNION ALL
SELECT CONVERT(decimal(3,0),ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) AS I
FROM N N1, N N2)
SELECT @SQL = STUFF((SELECT @CRLF + N'UNION' + @CRLF +
N'SELECT frm.[Weekday],' + @CRLF +
N' ' + FORMAT(T.I,'0') + N' AS Percentile,' + @CRLF +
N' PERCENTILE_DISC(' + FORMAT(T.I/100,'0.00') + N') WITHIN GROUP (ORDER BY frm.[n]) OVER(PARTITION BY frm.[Weekday]) AS n' + @CRLF +
N'FROM ##Temp AS frm'
FROM Tally T
ORDER BY T.I
FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,9,N'') + @CRLF +
N'ORDER BY Weekday, n, Percentile;'
--SELECT @SQL;
EXEC sys.sp_executesql @SQL;