Объединить строки в столбцы (НЕТ FOR XML PATH ('') и рекурсивные CTE) - SQL Server 2012 - PullRequest
0 голосов
/ 05 апреля 2020

У меня под рукой очень специфическая проблема.

Краткое введение: у меня есть две колонки в базе данных, которые мне нужны для "объединения групп", в MySQL я просто использовал бы GROUP_CONCAT, чтобы получить желаемый результат, в SQL Server 2017 и далее я бы использовал STRING_AGG, проблема, которая у меня есть, в SQL Server 2012, который не имеет этой функции.

Теперь, под в обычных обстоятельствах я бы использовал FOR XML PATH(''), чтобы получить решение, это нежизнеспособно, так как я запускаю запрос из редактора в третьем исходном приложении, ошибка, которую я получаю,

FOR XML PATH ('') нельзя использовать внутри курсора

Ради аргумента давайте предположим, что использование этой функции совершенно не подлежит сомнению.

Я пытался использовать рекурсивный CTE, однако он не жизнеспособен из-за времени выполнения, UNION ALL требует слишком много ресурсов и не может выполняться должным образом (я использую данные для отчетов).

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

Пример: Ввод:

col1  col2 
1     a
1     b
2     a
3     c

Выход:

col1  col2 
1     a/b
2     a
3     c

У кого-нибудь есть креативная идея, как это сделать?

Ответы [ 2 ]

2 голосов
/ 05 апреля 2020

Если вам известно максимальное количество значений, которые необходимо объединить вместе, вы можете использовать условное агрегирование:

select col1,
       stuff( concat(max(case when seqnum = 1 then '/' + col2 end),
                     max(case when seqnum = 2 then '/' + col2 end),
                     max(case when seqnum = 3 then '/' + col2 end),
                     max(case when seqnum = 4 then '/' + col2 end),
                     max(case when seqnum = 5 then '/' + col2 end)
                    ), 1, 1, ''
            ) as col2s                     
from (select t.*, 
             row_number() over (partition by col1 order by col2) as seqnum
      from t
     ) t
group by col1;

Максимальное число можно получить, используя:

select top (1) count(*)
from t
group by col1;
2 голосов
/ 05 апреля 2020

Ваш пример выходных данных кажется неправильным, поскольку значение a / b должно соответствовать значению 2.

попробуйте следующее:

declare @t table (col1  int, col2 varchar(100))
insert into @t select 1, 'a'
insert into @t select 2, 'b'
insert into @t select 2, 'a'
insert into @t select 3, 'c'

declare @final_table table (col1  int, col2 varchar(100), col2_all varchar(1000))
insert into @final_table (col1, col2)
select * from @t

declare @col2_all varchar(1000)
declare @Name sysname

update  @final_table 
SET @col2_all = col2_all = COALESCE(CASE COALESCE(@Name, '') 
                                        WHEN col1 THEN @col2_all + '/' + col2
                                        ELSE col2 END, ''), 
                                    @Name = col1;

select col1, col2_grouped = MAX(col2_all)
from @final_table
group by col1

Использование CTE:

;with cte(col1,col2_grouped,rn)
as
(
  select col1, col2 , rn=ROW_NUMBER() over (PARTITION by col1 order by col1)
  from @t
)
,cte2(col1,final_grouped,rn)
as
(
select col1, convert(varchar(max),col2_grouped), 1 from cte where rn=1
union all
select cte2.col1, convert(varchar(max),cte2.final_grouped+'/'+cte.col2_grouped), cte2.rn+1
from cte2
inner join cte on cte.col1 = cte2.col1 and cte.rn=cte2.rn+1
)
select col1, MAX(final_grouped) col2_grouped from cte2 group by col1

См. Дб <> скрипка здесь .

...