Làm sao tôi có thể lấy:
id Name Value
1 A 4
1 B 8
2 C 9
đến
id Column
1 A:4, B:8
2 C:9
Làm sao tôi có thể lấy:
id Name Value
1 A 4
1 B 8
2 C 9
đến
id Column
1 A:4, B:8
2 C:9
Câu trả lời:
Không cần vòng lặp CURSOR, WHILE hoặc Hàm do người dùng xác định .
Chỉ cần sáng tạo với FOR XML và PATH.
[Lưu ý: Giải pháp này chỉ hoạt động trên SQL 2005 trở lên. Câu hỏi ban đầu không chỉ định phiên bản đang sử dụng.]
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
Nếu là SQL Server 2017 hoặc SQL Server Vnext, SQL Azure, bạn có thể sử dụng chuỗi_agg như dưới đây:
select id, string_agg(concat(name, ':', [value]), ', ')
from #YourTable
group by id
sử dụng đường dẫn XML sẽ không kết hợp hoàn hảo như bạn mong đợi ... nó sẽ thay thế "&" bằng "& amp;" và cũng sẽ gây rối với <" and ">
... có thể một vài thứ khác, không chắc chắn ... nhưng bạn có thể thử điều này
Tôi đã gặp một cách giải quyết cho việc này ... bạn cần thay thế:
FOR XML PATH('')
)
với:
FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')
... Hoặc NVARCHAR(MAX)
nếu đó là những gì bạn đang sử dụng.
Tại sao địa ngục không SQL
có chức năng tổng hợp nối? đây là một Pita.
Tôi chạy vào một vài vấn đề khi tôi đã cố gắng chuyển đổi đề nghị Kevin Fairchild để làm việc với các chuỗi có chứa khoảng trắng và ký tự đặc biệt XML ( &
, <
, >
) được mã hóa.
Phiên bản cuối cùng của mã của tôi (không trả lời câu hỏi ban đầu nhưng có thể hữu ích cho ai đó) trông như thế này:
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. > < etc*/
).value('.','VARCHAR(MAX)')
,1,2,'') as NameValues
FROM #YourTable Results
GROUP BY ID
DROP TABLE #YourTable
Thay vì sử dụng một khoảng trắng làm dấu phân cách và thay thế tất cả các khoảng trắng bằng dấu phẩy, nó chỉ sử dụng trước một dấu phẩy và khoảng trắng cho mỗi giá trị sau đó sử dụng STUFF
để xóa hai ký tự đầu tiên.
Mã hóa XML được chăm sóc tự động bằng cách sử dụng lệnh TYPE .
Một tùy chọn khác sử dụng Sql Server 2005 trở lên
---- 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
Cài đặt các Tập hợp SQLCLR từ http://groupconcat.codeplex.com
Sau đó, bạn có thể viết mã như thế này để nhận được kết quả mà bạn yêu cầu:
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 trở lên cho phép bạn tạo các hàm tổng hợp tùy chỉnh của riêng mình , bao gồm cả những thứ như ghép nối - xem mẫu ở cuối bài viết được liên kết.
Tám năm sau ... Microsoft SQL Server vNext Database Engine cuối cùng đã tăng cường Transact-SQL để hỗ trợ trực tiếp nối chuỗi được nhóm. Phiên bản Xem trước Kỹ thuật Cộng đồng 1.0 đã thêm chức năng STRING_AGG và CTP 1.1 đã thêm mệnh đề FORIN GROUP cho chức năng STRING_AGG.
Tham khảo: https://msdn.microsoft.com/en-us/l Library / mt775028.aspx
Đây chỉ là một bổ sung cho bài viết của Kevin Fairchild (rất thông minh) Tôi đã có thể thêm nó dưới dạng một nhận xét, nhưng tôi chưa có đủ điểm :)
Tôi đã sử dụng ý tưởng này cho một khung nhìn mà tôi đang thực hiện, tuy nhiên các mục tôi đang kết hợp các không gian chứa. Vì vậy, tôi đã sửa đổi mã một chút để không sử dụng khoảng trắng làm dấu phân cách.
Một lần nữa cảm ơn vì cách giải quyết tuyệt vời 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
Trong Oracle, bạn có thể sử dụng hàm tổng hợp LISTAGG.
Hồ sơ gốc
name type
------------
name1 type1
name2 type2
name2 type3
Sql
SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name
Kết quả là
name type
------------
name1 type1
name2 type2; type3
Loại câu hỏi này được hỏi ở đây rất thường xuyên, và giải pháp sẽ phụ thuộc rất nhiều vào các yêu cầu cơ bản:
https://stackoverflow.com/search?q=sql+pOLL
và
https://stackoverflow.com/search?q=sql+concatenate
Thông thường, không có cách nào chỉ có SQL để thực hiện việc này mà không có sql động, hàm do người dùng xác định hoặc con trỏ.
Chỉ cần thêm vào những gì Cade nói, đây thường là một thứ hiển thị mặt trước và do đó nên được xử lý ở đó. Tôi biết rằng đôi khi việc viết một cái gì đó 100% bằng SQL dễ dàng hơn cho những thứ như xuất tệp hoặc các giải pháp "chỉ SQL" khác, nhưng hầu hết các lần ghép này nên được xử lý trong lớp hiển thị của bạn.
Đừng cần một con trỏ ... một vòng lặp while là đủ.
------------------------------
-- 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
Chúng ta hãy làm rất đơn giản:
SELECT stuff(
(
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
FOR XML PATH('')
)
, 1, 2, '')
Thay thế dòng này:
select ', ' + x from (SELECT 'xxx' x union select 'yyyy') tb
Với truy vấn của bạn.
không thấy bất kỳ câu trả lời áp dụng chéo nào, cũng không cần trích xuất xml. Đây là một phiên bản hơi khác với những gì Kevin Fairchild đã viết. Nó nhanh hơn và dễ sử dụng hơn trong các truy vấn phức tạp hơn:
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
Bạn có thể cải thiện hiệu suất đáng kể theo cách sau nếu nhóm bằng cách chứa hầu hết một mục:
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
Sử dụng chức năng thay thế và cho JSON PATH
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
Đối với dữ liệu mẫu và nhiều cách khác bấm vào đây
Nếu bạn đã bật clr, bạn có thể sử dụng thư viện Group_Concat từ GitHub
GROUP_CONCAT()
chức năng tổng hợp của nó , nhưng việc giải quyết nó trên Microsoft SQL Server khó xử hơn. Xem câu hỏi SO sau đây để được trợ giúp: " Làm thế nào để có được nhiều bản ghi so với một bản ghi dựa trên mối quan hệ? "