从一列中选择值的所有组合

时间:2019-04-09 09:20:59

标签: sql sql-server

我需要从表中的一列返回所有值的组合。结果应排序。

----------------------
Table A
----------------------
ID      TEXT
----------------------
100     AAA
100     BBB
100     CCC
200     DDD
200     EEE

预期结果:

100     /AAA
100     /BBB
100     /CCC
100     /AAA/BBB
100     /AAA/CCC
100     /BBB/CCC
100     /AAA/BBB/CCC
200     /DDD
200     /EEE
200     /DDD/EEE

产生的select语句应该能够成为另一个select的一部分。

我已经尝试过了,它似乎正在工作,但是我不能将其用作子查询。

WITH cte ( combination, curr ) AS (
  SELECT CAST( t.COL AS VARCHAR(80) ),
         t.COL
  FROM   TABLE_A t
  UNION ALL
  SELECT CAST( c.combination + '/' + CAST( t.COL AS VARCHAR(3) ) AS VARCHAR(80) ), t.COL
  FROM   TABLE_A t
         INNER JOIN
         cte c
         ON ( c.curr < t.COL )
)
SELECT '/' + combination FROM cte

2 个答案:

答案 0 :(得分:1)

您可以为此使用recursive CTE。问题是您缺少正确连接下一个值的行号(而从未与前一个值连接)。我想这就是您想要的,因为您在结果中包括了路径/AAA/BBB但没有包括/BBB/AAA,因此AAA的记录必须与BBB联接,但记录与{{1} }不能与BBB一起使用,因此需要一种数据中不存在的特定排序方法。

我用AAA模拟了一个行号,您可以将IDENTITY与所需的任何ROW_NUMBER()一起使用。

设置

OVER(PARTITION BY ID ORDER BY <expression or column> )

解决方案

IF OBJECT_ID('tempdb..#Values') IS NOT NULL
    DROP TABLE #Values

CREATE TABLE #Values(
    RowID INT IDENTITY,
    ID INT,
    Text VARCHAR(100))

INSERT INTO #Values (
    ID,
    Text)
VALUES
    (100, 'AAA'),
    (100, 'BBB'),
    (100, 'CCC'),
    (200, 'DDD'),
    (200, 'EEE')

结果:

;WITH RecursiveJoins AS
(
    -- Anchor (original row)
    SELECT
        OriginRowID = V.RowID,
        CurrentRowID = V.RowID,
        ID = V.ID,
        Path = CONVERT(VARCHAR(MAX), '/' + V.Text),
        RecursionLevel = 0
    FROM
        #Values AS V

    UNION ALL

    -- Recursion (add any value with the same ID and higher RowID)
    SELECT
        OriginRowID = R.OriginRowID,
        CurrentRowID = V.RowID,
        ID = R.ID,
        Path = R.Path + '/' + V.Text,
        RecursionLevel = R.RecursionLevel + 1
    FROM
        RecursiveJoins AS R
        INNER JOIN #Values AS V ON
            R.ID = V.ID AND
            R.CurrentRowID < V.RowID
)
SELECT
    R.ID,
    R.Path,
    R.RecursionLevel
FROM
    RecursiveJoins AS R
ORDER BY
    R.ID,
    R.RecursionLevel,
    R.Path

答案 1 :(得分:0)

在这里,下面的查询将为您提供预期的输出:

在此处创建临时表以执行该操作:

  select * into #tt from (
  select '100' as ID,'AAA' as TEXT
  union all 
  select '100' as ID,'BBB' as TEXT
 union all 
  select '100' as ID,'CCC' as TEXT
 union all 
 select '200' as ID,'DDD' as TEXT
 union all 
 select '200' as ID,'EEE' as TEXT
)a

select * from #tt 
GO

从这里开始您的实际问题解决方案:

WITH cte ( ID,Val, curr ) AS (
  SELECT t.ID,CAST( t.[TEXT] AS VARCHAR(max) ),
        t.[TEXT]
  FROM   #tt t
  where t.id = 100
 UNION ALL
 SELECT t.ID, CAST( c.Val + '/' + CAST( t.[TEXT] AS VARCHAR(max) ) AS VARCHAR(max) ),
      t.[TEXT]
 FROM   #tt t
     INNER JOIN
     cte c
     ON ( c.curr < t.[TEXT] )
     where t.id = 100
)
,cte2 ( ID,Val, curr ) AS (
 SELECT t.ID,CAST( t.[TEXT] AS VARCHAR(max) ),
       t.[TEXT]
 FROM   #tt t
 where t.id = 200
  UNION ALL
  SELECT t.ID, CAST( c.Val + '/' + CAST( t.[TEXT] AS VARCHAR(max) ) AS VARCHAR(max) 
),
     t.[TEXT]
 FROM   #tt t
      INNER JOIN
      cte2 c
      ON ( c.curr < t.[TEXT] )
     where t.id = 200
)

SELECT ID,concat('/',Val)
FROM cte 
union all 
SELECT ID,concat('/',Val)
FROM cte2 
order by 1