回答
沒有光標,while循環或用戶定義函數需要。
只需要用FOR XML和PATH進行創意。
[注意:此解決方案僅適用於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
這類問題是經常在這裏問,該解決方案將依賴大量的潛在需求:
https://stackoverflow.com/search?q=sql+pivot
and
https://stackoverflow.com/search?q=sql+concatenate
通常,在沒有動態sql,用戶定義的函數或遊標的情況下,不存在僅使用SQL的方法。
不正確。 cyberkiwi使用cte:s的解決方案是純粹的sql,沒有任何廠商特定的hackery。 – 2013-07-25 11:24:04
在提問和回答時,我不會將遞歸CTE計算爲非常便攜,但現在由Oracle支持。最好的解決方案將取決於平臺。對於SQL Server,它很可能是FOR XML技術或客戶CLR聚合。 – 2013-07-25 15:11:32
所有問題的最終答案? http://stackoverflow.com/search?q=[無論什麼問題] – 2016-12-08 11:07:12
只是爲了增加凱德所說的,這通常是一個前端顯示的東西,因此應該在那裏處理。我知道,有時在SQL中爲文件導出或其他「僅SQL」解決方案寫入100%的東西比較容易,但大多數情況下,這種串聯應該在顯示層處理。
分組現在是一個前端顯示的東西?連接分組結果集中的一列有很多有效方案。 – MGOwen 2016-08-03 03:21:14
不需要光標... 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
請參閱:[不良習慣踢:思考WHILE循環不是遊標](http://sqlblog.com/blogs/aaron_bertrand/archive/2012/01/26/the-fallacy-that-a-while- loop-isn-ta-cursor.aspx) – 2015-03-09 19:17:38
@marc_s也許更好的批評是PRIMARY KEY應該在表變量上聲明。 – 2015-03-10 02:19:21
@marc_s在進一步的檢查中,這篇文章是一個虛假 - 幾乎所有關於沒有IO測量的性能討論。我確實瞭解LAG - 非常感謝。 – 2015-03-10 04:34:45
SQL Server 2005和更高版本允許你創建自己的custom aggregate functions,包括搞什麼concatenation-看到樣品在鏈接的文章的底部。
使用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
這僅僅是一個除了凱文飛兆半導體後(順便說一句非常聰明)的另一種選擇。我會添加它作爲評論,但我還沒有足夠的積分:)
我正在使用這個想法我正在處理的視圖,但是我concudyating項目包含空格。所以我稍微修改了代碼,不使用空格作爲分隔符。
再次感謝非常酷的解決方法凱文!
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
我遇到了幾個問題,當我試圖轉換凱文飛兆半導體的建議包含空格和被編碼的特殊XML字符(&
,<
,>
)字符串工作。
我的代碼的最終版本(不回答原來的問題,但可能是有用的人)看起來是這樣的:
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
而不是使用空格作爲分隔符,並更換所有的空間用逗號,它只是預先爲每個值預留逗號和空格,然後使用STUFF
刪除前兩個字符。
XML編碼通過使用TYPE指令自動處理。
使用XML路徑將不會像您所期望的那樣完美連接......它會將「&」替換爲「& amp」並且還將惹<" and ">
......也許其他一些事情,不知道...但你可以試試這個
我碰到一個解決辦法來爲這個......你需要更換:
FOR XML PATH('')
)
有:
FOR XML PATH(''),TYPE
).value('(./text())[1]','VARCHAR(MAX)')
...或者NVARCHAR(MAX)
如果那是你使用的是什麼。
爲什麼地獄不SQL
有一個連接集合函數?這是一個PITA。
在Oracle中,您可以使用LISTAGG聚合函數。 一個例子是:
name type
------------
name1 type1
name2 type2
name2 type3
SELECT name, LISTAGG(type, '; ') WITHIN GROUP(ORDER BY name)
FROM table
GROUP BY name
會導致:
name type
------------
name1 type1
name2 type2; type3
讓我們非常簡單:
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
與您查詢。
可以提高性能顯著以下方式,如果組由主要包含了一個項目:
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
從http://groupconcat.codeplex.com
安裝SQLCLR聚集然後,你可以寫這樣的代碼來獲取你問的結果爲:
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;
八年後...... Microsoft SQL Server vNext數據庫引擎終於增強了Transact-SQL以直接支持ort分組字符串連接。社區技術預覽版本1.0添加了STRING_AGG函數,並且CTP 1.1爲STRING_AGG函數添加了WITHIN GROUP子句。
沒有看到任何跨應用的答案,也沒有必要對XML提取。這是Kevin Fairchild寫的一個稍微不同的版本。它的速度更快和更容易使用更復雜的查詢:如果是SQL服務器2017年或SQL Server Vnext,SQL Azure中您可以使用如下string_agg
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
:
select id, string_agg(concat(name, ':', [value]), ', ')
from #YourTable
group by id
- 1. 如何使用GROUP BY連接SQL Server中的不同列?
- 2. 如何使用sql中的group by子句替換字符串?
- 3. SQL Server連接字符串
- 4. SQL Server連接字符串
- 5. SQL Server連接字符串
- 6. SQL Server連接字符串
- 7. 如何使用SQL Server中的ID連接字符串?
- 8. 的SQL Server:用字符串連接
- 9. 在SQL Server中使用RollUp和Group By?
- 10. SQL Server 2008 GROUP BY
- 11. SQL Server GROUP BY NULL
- 12. 如何使用SQL Server CE的動態連接字符串?
- 13. 在SQL Server 2005中連接字符串
- 14. SQL Server實例的字符串連接
- 15. SQL Server實例的連接字符串
- 16. SQL Server的ADO.Net連接字符串
- 17. 如何在Sql Server中使用Group By與動態SQL查詢
- 18. 遠程SQL Server的連接字符串
- 19. SQL Server 2005的PDO連接字符串
- 20. SQL Server的連接字符串?
- 21. 域上的SQL Server連接字符串
- 22. 模擬SUM和GROUP BY的字符串連接
- 23. SQL Server Express的連接字符串
- 24. sql-server的dbext連接字符串
- 25. SQL Server Express 2008連接字符串
- 26. SQL Server連接字符串問題?
- 27. SQL:使用字符串數據的GROUP BY
- 28. SQL Server數據庫連接字符串
- 29. SQL Server連接字符串問題
- 30. c#2008 SQL Server Express連接字符串
這種類型的問題就解決了使用它的`GROUP_CONCAT()`聚合函數很容易在MySQL上解決,但在Microsoft SQL Server上解決這個問題則更加棘手。請參閱以下問題尋求幫助: 「[如何根據關係獲取多個記錄對一個記錄?](http://stackoverflow.com/questions/102317/how-to-get-multiple-records-against-one - 基於記錄的關係)「 – 2008-11-07 19:21:41
每個使用微軟賬戶的人都應該投票選擇一個更簡單的連接解決方案:https://connect.microsoft.com/SQLServer/feedback/details/427987/olap-function-for-string -concatenation – 2015-07-31 10:45:55
您可以使用此處找到的SQLCLR聚合作爲替代,直到T-SQL得到增強:http://groupconcat.codeplex.com – 2016-03-19 03:29:57