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

问题描述 投票:2回答:2

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

----------------------
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
sql sql-server
2个回答
1
投票

你可以使用recursive CTE。问题是你缺少一个行号来正确加入下一个值(并且永远不会违背前一个值)。我认为这是你想要的,因为你在你的结果中包含路径/AAA/BBB而不是/BBB/AAA所以AAA的记录必须与BBB一起加入,但是记录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

结果:

ID      Path            RecursionLevel
100     /AAA            0
100     /BBB            0
100     /CCC            0
100     /AAA/BBB        1
100     /AAA/CCC        1
100     /BBB/CCC        1
100     /AAA/BBB/CCC    2
200     /DDD            0
200     /EEE            0
200     /DDD/EEE        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
© www.soinside.com 2019 - 2024. All rights reserved.