Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 生成列名的递归笛卡尔积_Sql_Recursion_Pivot - Fatal编程技术网

Sql 生成列名的递归笛卡尔积

Sql 生成列名的递归笛卡尔积,sql,recursion,pivot,Sql,Recursion,Pivot,我的问题是基于SQL的 我有一个名为SC的有效分组表,其中的分组是char2 所以我想算出这个分组的所有排列。为了做到这一点,使用了许多内部连接到SC的别名 即 我得到了这个结果 这里有两个非常好的结果 我可以为新列命名,因为我正在为表添加别名 我可以运行结果的行数 我的问题是,这不是动态的 我希望在不使用动态SQL的情况下有效地参数化表联接的组数 使用递归CTE和pivot的组合可以实现这一点吗 我尝试了以下方法,但结果不正确 ;WITH cte AS ( SELECT 1 AS G

我的问题是基于SQL的

我有一个名为SC的有效分组表,其中的分组是char2

所以我想算出这个分组的所有排列。为了做到这一点,使用了许多内部连接到SC的别名

我得到了这个结果

这里有两个非常好的结果

我可以为新列命名,因为我正在为表添加别名 我可以运行结果的行数 我的问题是,这不是动态的

我希望在不使用动态SQL的情况下有效地参数化表联接的组数

使用递归CTE和pivot的组合可以实现这一点吗

我尝试了以下方法,但结果不正确

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