Выберите все комбинации значений из одного столбца - PullRequest
2 голосов
/ 09 апреля 2019

Мне нужно вернуть все комбинации значений из одного столбца в таблице. Результат должен быть отсортирован.

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

Полученный оператор выбора должен быть частью другого выбора.

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

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 ]

1 голос
/ 09 апреля 2019

Для этого вы можете использовать рекурсивный 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 голосов
/ 09 апреля 2019

Здесь, ниже, запрос даст вам ожидаемый результат:

Здесь Создание временной таблицы для выполнения операции:

  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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...