Sql 使用带窗口函数的递归CTE

Sql 使用带窗口函数的递归CTE,sql,sql-server,Sql,Sql Server,我有一些数据,我想计算分组变量工作日内n的百分位数。我可以用一个while循环来做这个,但是我试着用一个CTE。当我尝试转换为CTE时,我得到: PERCENTILE_DISC函数的输入参数必须为常量 如何在递归CTE中使用窗口函数 将假数据集设为临时表 While循环解决方案 尝试使用递归CTE和错误消息 你不能使用rCTE,或者最好是计数。正如状态和错误告诉您的,第一个参数必须是文本;列的值不是文本,因此不能使用 您可以使用动态语句来执行此操作,但这并不理想: DECLARE @SQL nv

我有一些数据,我想计算分组变量工作日内n的百分位数。我可以用一个while循环来做这个,但是我试着用一个CTE。当我尝试转换为CTE时,我得到:

PERCENTILE_DISC函数的输入参数必须为常量

如何在递归CTE中使用窗口函数

将假数据集设为临时表

While循环解决方案

尝试使用递归CTE和错误消息


你不能使用rCTE,或者最好是计数。正如状态和错误告诉您的,第一个参数必须是文本;列的值不是文本,因此不能使用

您可以使用动态语句来执行此操作,但这并不理想:

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;
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
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
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;