Sql 生成列名的递归笛卡尔积
我的问题是基于SQL的 我有一个名为SC的有效分组表,其中的分组是char2 所以我想算出这个分组的所有排列。为了做到这一点,使用了许多内部连接到SC的别名 即 我得到了这个结果 这里有两个非常好的结果 我可以为新列命名,因为我正在为表添加别名 我可以运行结果的行数 我的问题是,这不是动态的 我希望在不使用动态SQL的情况下有效地参数化表联接的组数 使用递归CTE和pivot的组合可以实现这一点吗 我尝试了以下方法,但结果不正确Sql 生成列名的递归笛卡尔积,sql,recursion,pivot,Sql,Recursion,Pivot,我的问题是基于SQL的 我有一个名为SC的有效分组表,其中的分组是char2 所以我想算出这个分组的所有排列。为了做到这一点,使用了许多内部连接到SC的别名 即 我得到了这个结果 这里有两个非常好的结果 我可以为新列命名,因为我正在为表添加别名 我可以运行结果的行数 我的问题是,这不是动态的 我希望在不使用动态SQL的情况下有效地参数化表联接的组数 使用递归CTE和pivot的组合可以实现这一点吗 我尝试了以下方法,但结果不正确 ;WITH cte AS ( SELECT 1 AS G
;WITH cte AS
(
SELECT 1 AS GROUPNUMBER
UNION ALL
SELECT GROUPNUMBER + 1 AS GROUPNUMBER
FROM
(SELECT * FROM CTE) AS CTE /*this is the recursive call which starts the recursion*/
WHERE
GROUPNUMBER < 10 /* Terminating condition */
)
SELECT *
FROM
(SELECT
A.GROUPNUMBER, A.GROUPS AS GROUPSA, B.GROUPS AS GROUPSB,
ROW_NUMBER() OVER (PARTITION BY A.GROUPS ORDER BY A.GROUPS) AS Z
FROM
(SELECT * FROM SC, cte) AS A
INNER JOIN
(SELECT * FROM SC, cte) AS B ON 1 = 1
) AS X
PIVOT
(MAX(X.GROUPSB)
FOR Z IN ([2],[3],[3],[4],[5],[6],[7],[8],[9],[10])
) AS P
谢谢没有动态sql?
如果您不介意sql返回固定数量的列,那么这是可能的。
甚至不使用枢轴
示例有4个数字列,但@MaxLvl较低
雷克斯试验机试验
但如果动态Sql是一种选择呢?
下面是一个例子:
-- Using a temporary table for demonstration
IF OBJECT_ID('tempdb..#SC') IS NOT NULL DROP TABLE #SC;
CREATE TABLE #SC ([Groups] CHAR(2) PRIMARY KEY);
INSERT INTO #SC ([Groups]) VALUES
('AB'),('AC'),('AD'),('BC'),('BD'),('CD');
DECLARE @MaxLvl INT = 3;
DECLARE @DynamicSql VARCHAR(max);
DECLARE @Fields VARCHAR(max) = 'SC1.[Groups]';
DECLARE @AliasedFields VARCHAR(max) = 'SC1.[Groups] AS [1]';
DECLARE @Joins VARCHAR(max) = 'FROM #SC AS SC1';
DECLARE @Lvl INT = 1;
WHILE @Lvl < @MaxLvl
BEGIN
SET @Lvl = @Lvl + 1;
SET @Fields = CONCAT(@Fields,', ','SC',@Lvl,'.[Groups]');
SET @AliasedFields = CONCAT(@AliasedFields,',',CHAR(10),'SC',@Lvl,'.[Groups] AS [',@Lvl,']');
SET @Joins = CONCAT(@Joins,CHAR(10),'CROSS JOIN #SC AS SC', @Lvl);
END;
SET @DynamicSql = CONCAT('SELECT ',
CHAR(10), 'ROW_NUMBER() OVER (ORDER BY ', @Fields, ') AS RN,',
CHAR(10), @AliasedFields ,
CHAR(10), @Joins,
CHAR(10), 'ORDER BY ', @Fields);
-- select @DynamicSql AS DynamicSql;
EXEC(@DynamicSql);
在rextester上测试如果没有动态SQL,则无法执行此操作。顺便说一句,1=1上作为Gr2的伪SC内部连接SC与作为Gr2@user2915906的SC交叉连接SC相同,只是为了提供信息,我已经包括了一个使用动态sql的示例。尚未对其进行测试,但多个交叉联接可能会提供比递归查询更好的性能。@user2915906如果这对您有效,您可以接受答案:
DECLARE @SC TABLE ([Groups] CHAR(2) PRIMARY KEY);
INSERT INTO @SC ([Groups]) VALUES
('AB'),('AC'),('AD'),('BC'),('BD'),('CD');
DECLARE @MaxLvl INT = 3;
;WITH CTE AS
(
SELECT Groups AS Base, 1 Lvl,
CAST (Groups AS VARCHAR(MAX)) AS ListGroups,
Groups AS [1],
charnull AS [2],
charnull AS [3],
charnull AS [4]
FROM @SC
CROSS APPLY (SELECT CAST(NULL AS CHAR(2)) AS charnull) ch
UNION ALL
SELECT c.Base, c.Lvl+1, c.ListGroups+','+t.Groups,
c.[1],
IIF(c.Lvl = 1, t.Groups, c.[2]),
IIF(c.Lvl = 2, t.Groups, c.[3]),
IIF(c.Lvl = 3, t.Groups, c.[4])
FROM CTE AS c
JOIN @SC AS t ON c.Lvl < @MaxLvl
)
SELECT
ROW_NUMBER() OVER (ORDER BY ListGroups) AS rn,
[1],[2],[3],[4]
FROM CTE
WHERE Lvl = @MaxLvl
ORDER BY ListGroups;
-- Using a temporary table for demonstration
IF OBJECT_ID('tempdb..#SC') IS NOT NULL DROP TABLE #SC;
CREATE TABLE #SC ([Groups] CHAR(2) PRIMARY KEY);
INSERT INTO #SC ([Groups]) VALUES
('AB'),('AC'),('AD'),('BC'),('BD'),('CD');
DECLARE @MaxLvl INT = 3;
DECLARE @DynamicSql VARCHAR(max);
DECLARE @Fields VARCHAR(max) = 'SC1.[Groups]';
DECLARE @AliasedFields VARCHAR(max) = 'SC1.[Groups] AS [1]';
DECLARE @Joins VARCHAR(max) = 'FROM #SC AS SC1';
DECLARE @Lvl INT = 1;
WHILE @Lvl < @MaxLvl
BEGIN
SET @Lvl = @Lvl + 1;
SET @Fields = CONCAT(@Fields,', ','SC',@Lvl,'.[Groups]');
SET @AliasedFields = CONCAT(@AliasedFields,',',CHAR(10),'SC',@Lvl,'.[Groups] AS [',@Lvl,']');
SET @Joins = CONCAT(@Joins,CHAR(10),'CROSS JOIN #SC AS SC', @Lvl);
END;
SET @DynamicSql = CONCAT('SELECT ',
CHAR(10), 'ROW_NUMBER() OVER (ORDER BY ', @Fields, ') AS RN,',
CHAR(10), @AliasedFields ,
CHAR(10), @Joins,
CHAR(10), 'ORDER BY ', @Fields);
-- select @DynamicSql AS DynamicSql;
EXEC(@DynamicSql);