CREATE TABLE #temp(name char(3)) INSERT INTO #temp VALUES ('CD') ,('AB') ,('LM') ,('BC') ,('GH') ,('KJ') ,('AB') DECLARE @cols AS NVARCHAR(MAX); SELECT @COLS = substring(list, 1, len(list) - 1) FROM (SELECT list = (SELECT DISTINCT name + ',' FROM #temp ORDER BY name + ',' FOR XML PATH(''), TYPE).value('.', 'nvarchar(MAX)')) AS T SELECT @COLS DROP TABLE #temp
Blog Stats
- 398,326 hits
-
Prashanth Jayaram
DB Technologist, Author, Blogger, Service Delivery Manager at CTS, Automation Expert, Technet WIKI Ninja, MVB and Powershell Geek My Profile: https://social.technet.microsoft.com/profile/prashanth jayaram/ http://www.sqlshack.com/author/prashanth/ http://codingsight.com/author/prashanthjayaram/ https://www.red-gate.com/simple-talk/author/prashanthjayaram/ http://www.sqlservercentral.com/blogs/powersql-by-prashanth-jayaram/ Connect Me: Twitter @prashantjayaram GMAIL powershellsql@gmail.com The articles are published in: http://www.ssas-info.com/analysis-services-articles/ http://db-pub.com/ http://www.sswug.org/sswugresearch/community/
Personal Links
Verified Services
Top 30 PowerShell bloggers of 2018
My Blog is ranked amongst the Top 50 SQL blogs worldwide
DZone MVB
Microsoft
Archives
- January 2021 (1)
- October 2020 (1)
- June 2019 (1)
- May 2019 (2)
- April 2019 (1)
- March 2019 (1)
- January 2019 (3)
- December 2018 (8)
- October 2018 (3)
- September 2018 (5)
- August 2018 (1)
- July 2018 (9)
- June 2018 (5)
- May 2018 (8)
- April 2018 (5)
- March 2018 (6)
- February 2018 (1)
- January 2018 (4)
- December 2017 (3)
- November 2017 (3)
- October 2017 (5)
- September 2017 (3)
- August 2017 (3)
- July 2017 (3)
- June 2017 (3)
- May 2017 (3)
- April 2017 (1)
- March 2017 (4)
- February 2017 (1)
- January 2017 (3)
- December 2016 (1)
- November 2016 (2)
- October 2016 (2)
- September 2016 (2)
- August 2016 (3)
- July 2016 (6)
- June 2016 (2)
- May 2016 (9)
- April 2016 (12)
- March 2016 (4)
- February 2016 (2)
- January 2016 (6)
- December 2015 (2)
- August 2015 (1)
- March 2015 (3)
- February 2015 (3)
- January 2015 (5)
- December 2014 (4)
- November 2014 (3)
- October 2014 (1)
- September 2014 (1)
- August 2014 (1)
- July 2014 (1)
- June 2014 (1)
- May 2014 (2)
- April 2014 (4)
- March 2014 (4)
- February 2014 (5)
- January 2014 (8)
- December 2013 (2)
- November 2013 (1)
- October 2013 (2)
- September 2013 (6)
- August 2013 (5)
- July 2013 (6)
- June 2013 (6)
- May 2013 (9)
- April 2013 (16)
Top Posts & Pages
- T-SQL - Read CSV files using OpenRowSet
- The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
- SQL vs NoSQL
- Simple Methods to Recover master.mdf File Password
- MongoDB - Insert,Update,Upsert and Delete Examples - CRUD
- Automation to list all TCP static and dynamic ports of SQL Server instances using PowerShell
- SQLCMD –Quick Copy of Files - Using Robocopy
- PowerShell - Script to Monitor Disk Space of a Group of servers - HTML Formatted Email Output
- PowerShell GUI Tool - Network Ping - Version 2
- Overview of File-group(s) and Piecemeal database restore operations in SQL Server
Categories
- AlwaysOn (1)
- awards (2)
- Backup and Restore (14)
- Citrix (1)
- databases_files (2)
- docker (5)
- Exchange (2)
- FileProperty (1)
- GDPR (1)
- GENERAL (3)
- Graph database (1)
- JSON (4)
- Logshipping on Linux (1)
- MongoDB (16)
- NoSQL (1)
- Philosophy (1)
- PowerShell (64)
- Python (4)
- Robocopy (2)
- SCCM (1)
- Security (3)
- Vulnerability (1)
- SETVAR (2)
- sp_msforeachDB (1)
- sp_MSforeachtable (1)
- SQL (99)
- SQL 2012 (4)
- SQL 2016 (11)
- SQL 2017 (7)
- SQL 2017 on Linux (5)
- SQL and Python (1)
- SQL AZURE (2)
- SQL Indexes (1)
- SQL Joins (1)
- SQL On Linux (1)
- SQL Ops Studio (1)
- SQL Server 2017 (11)
- SQL Server Backup (10)
- SQL Server DevOps (1)
- SQL Server Tools (1)
- SQL Server vNext (2)
- SQL String (1)
- SQL tools (2)
- SQL XML (1)
- SQLCMD (3)
- SSAS (4)
- SSRS (3)
- String handling (2)
- sysfiles (3)
- T-SQL (37)
- Uncategorized (42)
- Variable Passing (1)
- XenApp VDA (1)
- XenDesktop VDA (1)
- XML (2)
- Follow Prashanth Jayaram on WordPress.com
- January 24, 2021The big day is here.
- The Big DayOctober 25, 2016The big day is here.
I think FOR XML PATH is not needed to achieve the above. This can be resolved as below as well.
CREATE TABLE #temp(name char(3))
INSERT INTO #temp VALUES (‘CD’)
,(‘AB’)
,(‘LM’)
,(‘BC’)
,(‘GH’)
,(‘KJ’)
,(‘AB’)
DECLARE @cols AS NVARCHAR(MAX)=”;
SELECT @cols=@cols+name+’,’
FROM #temp
GROUP BY name
ORDER BY name
SELECT @cols
DROP TABLE #temp
LikeLike
Just to concatinate into a variable you don’t need to use FOR XML. Just concatinate in sql.
DECLARE @cols AS NVARCHAR(MAX)=”;
SELECT @cols = @cols + ‘,’ + name
FROM (SELECT DISTINCT name FROM #temp)a
ORDER BY name
SELECT STUFF(@cols,1,1,”)
LikeLike
Hi.
I think there’s an easier way to do that:
CREATE TABLE #temp(name char(3))
INSERT INTO #temp VALUES (‘CD’)
,(‘AB’)
,(‘LM’)
,(‘BC’)
,(‘GH’)
,(‘KJ’)
,(‘AB’)
declare @v varchar(max)=”
select @v=@v + name + ‘,’ from #temp
select @v
drop table #temp
BTW, the same way you can do a summarizing or multiplying for a column:
CREATE TABLE #temp(name int)
INSERT INTO #temp VALUES (2)
,(3)
,(4)
,(5)
,(6)
,(7)
,(8)
declare @v int = 1
select @v=@v * name from #temp
select @v
drop table #temp
LikeLike
— Here is another slick way to handle this problem. See replacement SELECT statement.
— I can’t take credit for this, but here is a brief explanation of what’s going on.
— 1. When @cols is declared it starts off as NULL
— 2. The first iteration through @cols + ‘,’ = NULL (NULL + anything = NULL)
— 3. COALESCE turns that NULL result into ” so no comma is added before the first entry
— 4. ” is appended to T.name to start the string
— 5. @cols = ‘AB’ after the first iteration
— 6. Each subsequent pass ‘,’ is appended to @cols before appending T.name.
SELECT @cols = COALESCE(@cols + ‘,’, ”) + T.name
FROM #temp AS T
ORDER BY T.name
LikeLike
Hi Prashanth,
Good post! Here’s an alternative:
CREATE TABLE #temp(name char(3))
INSERT INTO #temp VALUES (‘CD’)
,(‘AB’)
,(‘LM’)
,(‘BC’)
,(‘GH’)
,(‘KJ’)
,(‘AB’)
DECLARE @cols AS NVARCHAR(MAX);
SELECT @cols = ISNULL(@cols + ‘,’, ”) + [name]
FROM #temp
WHERE [name] IS NOT NULL
GROUP BY [name]
ORDER BY [name]
SELECT @COLS
DROP TABLE #temp
LikeLike
Another approach without XML PATH.
CREATE TABLE #temp(name VARCHAR(3))
INSERT INTO #temp VALUES (‘CD’)
,(‘AB’)
,(‘LM’)
,(‘BC’)
,(‘GH’)
,(‘KJ’)
,(‘AB’)
DECLARE @cols AS NVARCHAR(MAX);
SELECT @cols = ISNULL(@cols + ‘,’, ”) + name
FROM (SELECT DISTINCT TOP 100 PERCENT name FROM #temp ORDER BY 1) x
SELECT @cols
DROP TABLE #temp
LikeLike
I don’t remember when I first came across this technique, but it was published back in the early 2000’s. I turned it into a code-generating procedure that spits out code you can use to create a User-Defined Function, so that the “flattener” logic could be used in report views to collapse lists of values. Below is the code example from a presentation I did for the St. Louis SQL Server Users Group some time ago:
use Adventureworks
go
/* There is simple and elegant use the Coalsce() function to “Flatten” a column
to a delimited string. I first saw the technique in an article in T-SQL Solutions.
At first Glance, I could not believe that it would work, but it does and it performs better
than using a cursor or while loop to perform the same operation:
*/
Declare @w_resulttext varchar(max)
SELECT @w_resulttext = coalesce( @w_resulttext +’, ‘, ”) + [Name]
FROM production.ProductSubCategory where ProductCategoryID = 4
select @w_resulttext
/*
The trick to this technique is to use the coalesce function to insert the delimiter.
Here is how it works:
When processing the first row, the variable is null, so the second term of the coalesce
function appends the “empty string” to the variable, then the value from the first row is appended
All subsequent rows are handled by the first term of the coalesce() function, resulting in the
delimiter being appended to the variable prior to adding the next row’s value.
I had written a bunch of user-defined functions using cursors to “flatten” or “Pivot” data
for several parent-child tables. To simplify converting them all to this technique,
I wrote a helper proc to generate the code for the technique.
It generates a functioning code “template” that can be used directly or modified by
adding conditions or joins to other tables:
*/
go
create procedure sp__CreateFlattener
@p_table sysname
,@p_column sysname
,@p_delimeter varchar(20) = ‘,’
,@p_SQL varchar(max) = null OUTPUT
as
/*
Generate code snippet for collapsing row values into a single delimited string
Author: @sqlmonger
*/
set @p_SQL = ‘Declare @w_resulttext varchar(max)
SELECT @w_resulttext = coalesce( @w_resulttext +’ + char(39)
+ @p_delimeter
+ char(39) + ‘, ‘
+ char(39) + char(39) + ‘) + ‘ + @p_Column
+ char(13) + char(10) + ‘FROM ‘ + @p_table
+ char(13) + char(10) + ‘select @w_resulttext’
–print @p_sql — comment this out if you don’t want the results printed to message window
return 0
go
— dynamic useage: Note it always sends text of query via print command
declare @SQL varchar(max)
exec sp__createflattener @p_table = ‘production.ProductSubCategory’, @p_column = ‘[Name]’, @p_delimeter = ‘|’, @p_SQL = @SQL OUTPUT
–exec (@SQL)
print @sql
go
/*
— generated script:
Declare @w_resulttext varchar(max)
SELECT @w_resulttext = coalesce( @w_resulttext +’|’, ”) + [Name]
FROM production.ProductSubCategory
select @w_resulttext
*/
Declare @w_resulttext varchar(max)
SELECT @w_resulttext = coalesce( @w_resulttext +’|’, ”) + [Name]
FROM production.ProductSubCategory
select @w_resulttext
–turn the output into a function that can be used in other queries:
create function dbo.fn_FlattenProductSubCategory (@ProductCategoryID int)
returns varchar(max)
begin
Declare @w_resulttext varchar(max)
SELECT @w_resulttext = coalesce( @w_resulttext +’, ‘, ”) + [Name]
FROM production.ProductSubCategory
where ProductCategoryID = @ProductCategoryID
return @w_resulttext
end
go
— simple select using the function
select dbo.fn_FlattenProductSubCategory(4)
–as part of a multi-row record set
select ProductCategoryID
, name as ProductName
,dbo.fn_FlattenProductSubCategory(ProductCategoryID) as SubCategories
from Production.ProductCategory
LikeLike
Minor (obvious) cleanup:
The proposed solution(s) result in “AB ,BC ,CD ,GH ,KJ ,LM” which contains extra spaces.
SELECT @cols = REPLACE (ISNULL(@cols + ‘,’, ”) + name, ‘ ‘ , ”)
results in more compact string: “AB,BC,CD,GH,KJ,LM”.
LikeLike
This is a similar idea to the original post, but simpler, I think:
CREATE TABLE #temp (name CHAR(3))
INSERT INTO #temp
VALUES (‘CD’)
,(‘AB’)
,(‘LM’)
,(‘BC’)
,(‘GH’)
,(‘KJ’)
,(‘AB’)
DECLARE @cols AS NVARCHAR(MAX);
SELECT @cols = STUFF((SELECT ‘,’ + name
FROM #temp
ORDER BY name
FOR
XML PATH(”)
), 1, 1, ”)
SELECT @COLS
DROP TABLE #temp
LikeLike
Exactly what I needed to generate a semi-colon delimited email list with no dupes – THX 🙂
LikeLike