문제

어떻게 내가 가질까:

id       Name       Value
1          A          4
1          B          8
2          C          9

에게

id          Column
1          A:4, B:8
2          C:9
도움이 되었습니까?

해결책

커서, 루프 또는 사용자 정의 기능이 필요하지 않습니다..

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

다른 팁

SQL Server 2017 또는 SQL Server VNEXT 인 경우 SQL Azure는 다음과 같이 String_agg를 사용할 수 있습니다.

select id, string_agg(concat(name, ':', [value]), ', ')
    from #YourTable 
    group by id

XML 경로를 사용하면 예상대로 완벽하게 연결되지 않습니다 ... "&"& "로 대체하고 <" and ">... 어쩌면 몇 가지 다른 것들이 확실하지 않습니다 ...하지만 당신은 이것을 시도 할 수 있습니다

나는 이것에 대한 해결 방법을 발견했다 ... 당신은 교체해야한다 :

FOR XML PATH('')
)

와 함께:

FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')

...또는 NVARCHAR(MAX) 그게 당신이 사용하는 것입니다.

도대체 왜 그렇지 않습니다 SQL 컨텍스트 집계 기능이 있습니까? 이것은 피타입니다.

공백과 특수 XML 문자가 포함 된 문자열로 작업하기 위해 Kevin Fairchild의 제안을 변환하려고 시도했을 때 몇 가지 문제가 발생했습니다.&, <, >) 인코딩 된.

내 코드의 최종 버전 (원래 질문에 응답하지 않지만 누군가에게 유용 할 수 있음)은 다음과 같습니다.

CREATE TABLE #YourTable ([ID] INT, [Name] VARCHAR(MAX), [Value] INT)

INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'Oranges & Lemons',4)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (1,'1 < 2',8)
INSERT INTO #YourTable ([ID],[Name],[Value]) VALUES (2,'C',9)

SELECT  [ID],
  STUFF((
    SELECT ', ' + CAST([Name] AS VARCHAR(MAX))
    FROM #YourTable WHERE (ID = Results.ID) 
    FOR XML PATH(''),TYPE 
     /* Use .value to uncomment XML entities e.g. &gt; &lt; etc*/
    ).value('.','VARCHAR(MAX)') 
  ,1,2,'') as NameValues
FROM    #YourTable Results
GROUP BY ID

DROP TABLE #YourTable

공간을 구분 기자로 사용하고 모든 공간을 쉼표로 교체하는 대신 각 값에 쉼표와 공간을 사전 지불 한 다음 사용합니다. STUFF 처음 두 문자를 제거합니다.

XML 인코딩은 유형 지령.

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

SQLCLR 집계를 설치하십시오 http://groupconcat.codeplex.com

그런 다음 이와 같은 코드를 작성하여 요청한 결과를 얻을 수 있습니다.

CREATE TABLE foo
(
 id INT,
 name CHAR(1),
 Value CHAR(1)
);

INSERT  INTO dbo.foo
    (id, name, Value)
VALUES  (1, 'A', '4'),
        (1, 'B', '8'),
        (2, 'C', '9');

SELECT  id,
    dbo.GROUP_CONCAT(name + ':' + Value) AS [Column]
FROM    dbo.foo
GROUP BY id;

SQL Server 2005 이상 사용자 정의 집계 기능, 연결과 같은 것들을 포함하여 링크 된 기사의 맨 아래에있는 샘플을 참조하십시오.

8 년 후 ... Microsoft SQL Server VNEXT Database Engine은 마침내 그룹화 된 문자열 연결을 직접 지원하도록 Transact-SQL을 향상 시켰습니다. Community Technical Preview 버전 1.0은 String_Agg 함수를 추가하고 CTP 1.1은 String_Agg 함수의 그룹 절을 추가했습니다.

참조: https://msdn.microsoft.com/en-us/library/mt775028.aspx

예가 있습니다

Oracle에서는 listagg 집계 기능을 사용할 수 있습니다.

원래 기록

name   type
------------
name1  type1
name2  type2
name2  type3

SQL

SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name

의 결과

name   type
------------
name1  type1
name2  type2; type3

이런 종류의 질문은 여기서 자주 묻는다. 그리고 해결책은 기본 요구 사항에 크게 의존 할 것이다.

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

그리고

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

일반적으로 동적 SQL, 사용자 정의 함수 또는 커서 없이는 SQL 전용 방법이 없습니다.

Cade가 말한 것에 추가하기 위해, 이것은 일반적으로 프론트 엔드 디스플레이이므로 처리해야합니다. 파일 내보내기 또는 기타 "SQL 전용"솔루션과 같은 것에 대해 SQL에 100%를 쓰는 것이 더 쉽다는 것을 알고 있지만 대부분의 경우이 연결은 디스플레이 레이어에서 처리해야합니다.

이것은 Kevin Fairchild의 게시물에 추가 된 것입니다 (매우 영리합니다). 나는 그것을 댓글로 추가했을 것이지만 아직 충분한 점이 없다 :)

나는이 아이디어를 내가 작업하고있는 견해를 위해 사용하고 있었지만, 내가 연결하고 있던 항목에는 공간이 포함되어 있습니다. 따라서 공간을 구분자로 사용하지 않도록 코드를 약간 수정했습니다.

멋진 해결 방법 Kevin에 다시 한번 감사드립니다!

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], 
       REPLACE(REPLACE(REPLACE(
                          (SELECT [Name] + ':' + CAST([Value] AS VARCHAR(MAX)) as A 
                           FROM   #YourTable 
                           WHERE  ( ID = Results.ID ) 
                           FOR XML PATH (''))
                        , '</A><A>', ', ')
                ,'<A>','')
        ,'</A>','') AS NameValues 
FROM   #YourTable Results 
GROUP  BY ID 

DROP TABLE #YourTable 

커서가 필요하지 않습니다 ... while 루프만으로도 충분합니다.

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

매우 간단하게하자 :

SELECT stuff(
    (
    select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb 
    FOR XML PATH('')
    )
, 1, 2, '')

이 라인 교체 :

select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb

쿼리와 함께.

크로스 적용 답변은 보이지 않았으며 XML 추출이 필요하지 않습니다. Kevin Fairchild가 쓴 것과 약간 다른 버전이 있습니다. 더 복잡한 쿼리에서 더 빠르고 사용하기 쉽습니다.

   select T.ID
,MAX(X.cl) NameValues
 from #YourTable T
 CROSS APPLY 
 (select STUFF((
    SELECT ', ' + [Name] + ':' + CAST([Value] AS VARCHAR(MAX))
    FROM #YourTable 
    WHERE (ID = T.ID) 
    FOR XML PATH(''))
  ,1,2,'')  [cl]) X
  GROUP BY T.ID

Group By가 대부분 하나의 항목을 포함하는 경우 다음과 같은 성능을 향상시킬 수 있습니다.

SELECT 
  [ID],

CASE WHEN MAX( [Name]) = MIN( [Name]) THEN 
MAX( [Name]) NameValues
ELSE

  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

END

FROM #YourTable Results
GROUP BY ID
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top