Рекурсивное декартово произведение для генерации имен столбцов - PullRequest
0 голосов
/ 25 августа 2018

Мой вопрос основан на SQL

У меня есть таблица с именем SC допустимых группировок, подобная этой, где GROUP это char (2)

enter image description here

Итак, я хочу проработать все перестановки этой группировки.Для этого использовали множество внутренних объединений с псевдонимами SC

IE

SELECT 
    ROW_NUMBER() OVER ( ORDER BY sc.Groups ) as Permutation,
    SC.GROUPS AS Group1, 
    Gr2.GROUPS as Group2,
    Gr3.GROUPS as Group3
FROM 
    SC
INNER JOIN 
    SC AS Gr2 ON 1 = 1   
INNER JOIN 
    SC AS Gr3 ON 1 = 1 

И я получил такой результат

enter image description here

Здесь есть 2 результата, которые действительно хороши

  1. Я могу назвать новые столбцы, так как я создаю псевдонимы таблиц
  2. Я могу запустить номер строки результата

У меня проблема в том, что это не динамично.

Я бы хотел параметризовать количество групп (фактически, объединений таблиц) без использования динамического SQL

Возможно ли это с помощью комбинации рекурсивного CTE и сводной последовательности?

Я пыталсяследующее, но получил неправильный результат

;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

enter image description here

Спасибо

1 Ответ

0 голосов
/ 26 августа 2018

без динамического sql?
Тогда это возможно, если вы не возражаете, что sql возвращает фиксированное количество столбцов.
Даже без использования PIVOT.

Пример с 4 числовыми столбцами, но с более низким @MaxLvl

Тест на rextester здесь

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;

Но если бы Dynamic 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 здесь

...