2

我需要以遞歸交叉連接方式連接名稱。我不知道如何做到這一點,我嘗試了使用但沒有成功的CTE。連接遞歸交叉連接

我有這樣的一個表:

group_id | name 
--------------- 
13  | A 
13  | B 
19  | C 
19  | D 
31  | E 
31  | F 
31  | G 

所需的輸出:

combinations 
------------ 
ACE 
ACF 
ACG 
ADE 
ADF 
ADG 
BCE 
BCF 
BCG 
BDE 
BDF 
BDG 

當然,如果我添加了一個第四(或更多)組的結果應乘。

回答

2

本地PostgreSQL的語法:

SqlFiddleDemo

WITH RECURSIVE cte1 AS 
(
    SELECT *, DENSE_RANK() OVER (ORDER BY group_id) AS rn 
    FROM mytable 
),cte2 AS 
(
    SELECT 
    CAST(name AS VARCHAR(4000)) AS name, 
    rn 
    FROM cte1 
    WHERE rn = 1 
    UNION ALL 
    SELECT 
    CAST(CONCAT(c2.name,c1.name) AS VARCHAR(4000)) AS name 
    ,c1.rn 
    FROM cte1 c1 
    JOIN cte2 c2 
    ON c1.rn = c2.rn + 1 
) 
SELECT name as combinations 
FROM cte2 
WHERE LENGTH(name) = (SELECT MAX(rn) FROM cte1) 
ORDER BY name; 

前:

我希望,如果你不介意,我使用SQL Server語法:

示例:

CREATE TABLE #mytable(
    ID  INTEGER NOT NULL 
    ,TYPE  VARCHAR(MAX) NOT NULL 
); 
INSERT INTO #mytable(ID,TYPE) VALUES (13,'A'); 
INSERT INTO #mytable(ID,TYPE) VALUES (13,'B'); 
INSERT INTO #mytable(ID,TYPE) VALUES (19,'C'); 
INSERT INTO #mytable(ID,TYPE) VALUES (19,'D'); 
INSERT INTO #mytable(ID,TYPE) VALUES (31,'E'); 
INSERT INTO #mytable(ID,TYPE) VALUES (31,'F'); 
INSERT INTO #mytable(ID,TYPE) VALUES (31,'G'); 

主查詢:

WITH cte1 AS 
(
    SELECT *, rn = DENSE_RANK() OVER (ORDER BY ID) 
    FROM #mytable 
),cte2 AS 
(
    SELECT 
    TYPE = CAST(TYPE AS VARCHAR(MAX)), 
    rn 
    FROM cte1 
    WHERE rn = 1 
    UNION ALL 
    SELECT 
    [Type]  = CAST(CONCAT(c2.TYPE,c1.TYPE) AS VARCHAR(MAX)) 
    ,c1.rn 
    FROM cte1 c1 
    JOIN cte2 c2 
    ON c1.rn = c2.rn + 1 
) 
SELECT * 
FROM cte2 
WHERE LEN(Type) = (SELECT MAX(rn) FROM cte1) 
ORDER BY Type; 

LiveDemo

我假設的命令 「交叉聯接」 是依賴於上升ID。

  • CTE1產生DENSE_RANK()因爲你的ID中包含的差距
  • 與CTE2遞歸部分CONCAT
  • 主查詢只篩選出所需的長度和排序字符串
+0

太棒了!這是訣竅。你對這個命令的假設對於這個例子是正確的;-)實際上,我添加了一個顯示順序列;-) – frankhommers

1

遞歸查詢是簡單一點在Postgres:

WITH RECURSIVE t AS ( -- to produce gapless group numbers 
    SELECT dense_rank() OVER (ORDER BY group_id) AS grp, name 
    FROM tbl 
    ) 
, cte AS (
    SELECT grp, name 
    FROM t 
    WHERE grp = 1 

    UNION ALL 
    SELECT t.grp, c.name || t.name 
    FROM cte c 
    JOIN t ON t.grp = c.grp + 1 
    ) 
SELECT name AS combi 
FROM cte 
WHERE grp = (SELECT max(grp) FROM t) 
ORDER BY 1; 

基本邏輯與SQL Server version provided by @lad2025相同,我添加了一些小改進。

或者你可以使用一個簡單的版本如果你的組最大數量不能太大(不能非常大的,真的,因爲結果集呈指數增長)。最多5組:

WITH t AS ( -- to produce gapless group numbers 
    SELECT dense_rank() OVER (ORDER BY group_id) AS grp, name AS n 
    FROM tbl 
    ) 
SELECT concat(t1.n, t2.n, t3.n, t4.n, t5.n) AS combi 
FROM  (SELECT n FROM t WHERE grp = 1) t1 
LEFT JOIN (SELECT n FROM t WHERE grp = 2) t2 ON true 
LEFT JOIN (SELECT n FROM t WHERE grp = 3) t3 ON true 
LEFT JOIN (SELECT n FROM t WHERE grp = 4) t4 ON true 
LEFT JOIN (SELECT n FROM t WHERE grp = 5) t5 ON true 
ORDER BY 1; 

對於少數羣體而言可能會更快。 LEFT JOIN .. ON true即使缺少更高級別也可以使用此工作。 concat()忽略NULL值。請確定使用EXPLAIN ANALYZE進行測試。

SQL Fiddle顯示兩者。

+0

謝謝。我需要爲我的目標遞歸查詢。你的遞歸版本確實有點乾淨。我想我會用我的看法。 – frankhommers