Как использовать GROUP BY для конкатенации строк в SQL Server?

354
задан Adrian Carneiro 20 September 2011 в 03:46
поделиться

7 ответов

Никакому КУРСОРУ, Циклу с условием продолжения или Пользовательской Функции не было нужно .

Просто потребность быть творческим с ДЛЯ XML и ПУТИ.

[Примечание: Это решение только работает над SQL 2005 и позже. Исходный вопрос не определил используемую версию.]

CREATE TABLE #YourTable ([ID] INT, [Name] CHAR(1), [Value] INT)

INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'A',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'B',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)

SELECT 
  [ID],
  STUFF((
    SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) 
    FROM #YourTable 
    WHERE (ID = Results.ID) 
    FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR(MAX)')
  ,1,2,'') AS NameValues
FROM #YourTable Results
GROUP BY ID

DROP TABLE #YourTable
530
ответ дан Kevin Fairchild 23 November 2019 в 00:22
поделиться

Не нужен курсор... некоторое время, цикл достаточен.

------------------------------
-- Setup
------------------------------

DECLARE @Source TABLE
(
  id int,
  Name varchar(30),
  Value int
)

DECLARE @Target TABLE
(
  id int,
  Result varchar(max) 
)


INSERT INTO @Source(id, Name, Value) SELECT 1, 'A', 4
INSERT INTO @Source(id, Name, Value) SELECT 1, 'B', 8
INSERT INTO @Source(id, Name, Value) SELECT 2, 'C', 9


------------------------------
-- Technique
------------------------------

INSERT INTO @Target (id)
SELECT id
FROM @Source
GROUP BY id

DECLARE @id int, @Result varchar(max)
SET @id = (SELECT MIN(id) FROM @Target)

WHILE @id is not null
BEGIN
  SET @Result = null

  SELECT @Result =
    CASE
      WHEN @Result is null
      THEN ''
      ELSE @Result + ', '
    END + s.Name + ':' + convert(varchar(30),s.Value)
  FROM @Source s
  WHERE id = @id

  UPDATE @Target
  SET Result = @Result
  WHERE id = @id

  SET @id = (SELECT MIN(id) FROM @Target WHERE @id < id)
END

SELECT *
FROM @Target
5
ответ дан Amy B 23 November 2019 в 00:22
поделиться

Только для добавления к тому, что сказал Cade это обычно - вещь дисплея фронтенда и должно поэтому быть обработано там. Я знаю, что иногда легче записать чему-то 100% в SQL для вещей как экспорт файла или другом "SQL только" решения, но большинство времен эта конкатенация должно быть обработано в Вашем слое дисплея.

7
ответ дан Bridge 23 November 2019 в 00:22
поделиться

Этот вид вопроса спрашивают здесь очень часто, и решение собирается во многом зависеть от базовых требований:

https://stackoverflow.com/search? q=sql+pivot

и

https://stackoverflow.com/search? q=sql+concatenate

Как правило, нет никакого способа только для SQL сделать это или без динамического sql, пользовательской функции или без курсора.

7
ответ дан Community 23 November 2019 в 00:22
поделиться

SQL Server, включая который 2005 и позже позволяет Вам создавать свое собственное пользовательские агрегатные функции , для вещей как конкатенация - видит образец у основания связанной статьи.

12
ответ дан Joel Coehoorn 23 November 2019 в 00:22
поделиться

Используя Функцию Замены и ДЛЯ ПУТИ JSON

SELECT T3.DEPT, REPLACE(REPLACE(T3.ENAME,'{"ENAME":"',''),'"}','') AS ENAME_LIST
FROM (
 SELECT DEPT, (SELECT ENAME AS [ENAME]
        FROM EMPLOYEE T2
        WHERE T2.DEPT=T1.DEPT
        FOR JSON PATH,WITHOUT_ARRAY_WRAPPER) ENAME
    FROM EMPLOYEE T1
    GROUP BY DEPT) T3

Для демонстрационных данных и большего количества путей щелкают здесь

1
ответ дан 23 November 2019 в 00:22
поделиться

Другой вариант с использованием Sql Server 2005 и выше

---- test data
declare @t table (OUTPUTID int, SCHME varchar(10), DESCR varchar(10))
insert @t select 1125439       ,'CKT','Approved'
insert @t select 1125439       ,'RENO','Approved'
insert @t select 1134691       ,'CKT','Approved'
insert @t select 1134691       ,'RENO','Approved'
insert @t select 1134691       ,'pn','Approved'

---- actual query
;with cte(outputid,combined,rn)
as
(
  select outputid, SCHME + ' ('+DESCR+')', rn=ROW_NUMBER() over (PARTITION by outputid order by schme, descr)
  from @t
)
,cte2(outputid,finalstatus,rn)
as
(
select OUTPUTID, convert(varchar(max),combined), 1 from cte where rn=1
union all
select cte2.outputid, convert(varchar(max),cte2.finalstatus+', '+cte.combined), cte2.rn+1
from cte2
inner join cte on cte.OUTPUTID = cte2.outputid and cte.rn=cte2.rn+1
)
select outputid, MAX(finalstatus) from cte2 group by outputid
21
ответ дан 23 November 2019 в 00:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: