This question already has answers here:
Exclude a column using SELECT * [except columnA] FROM tableA?
(47 answers)
Closed 7 years ago.
I have a table with columns
a,b,c,d,e,f,g,...,z
Is it possible to write a simple query that will gives all columns except a without manualy specifing all other columns?
something that will be equivelant to:
Select b,c,d,e,f,g,h,...z
from TableG
To answer your question, you cannot do that directly, HOWEVER i found a solution for you.
The SELECT statement of SQL when using Physical table can only do SELECT * that will return all columns and SELECT Column1, Column2, Column3... for specific columns, there is no WHERE condition that will exclude 1 column name in the SELECT statement of SQL. How ever you can manipulate the table and the data the way you wanted it using temporary table
Solution:
Insert into temp table
Drop the column that you want to exclude from the temp table
Select all data from temp table.
SELECT * INTO #TempTable
FROM TableG
ALTER TABLE #TempTable
DROP COLUMN a
SELECT * FROM #TempTable
DROP TABLE #TempTable
I found the solution here: SQL exclude a column using SELECT * [except columnA] FROM tableA?
/************************************************************
Function To Split Strings
************************************************************/
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID('dbo.SplitString') IS NOT NULL
BEGIN
DROP FUNCTION dbo.SplitString
END
GO
create function [dbo].[SplitString]
(
#String varchar(max),
#Delimiter char(1)
)
returns #SplittedValues table
(
str_item varchar(100) primary key
)
as
begin
declare #SplitLength int
while len(#String) > 0
begin
select #SplitLength = (case charindex(#Delimiter,#String) when 0 then
len(#String) else charindex(#Delimiter,#String) -1 end)
insert into #SplittedValues
select substring(#String,1,#SplitLength)
select #String = (case (len(#String) - #SplitLength) when 0 then ''
else right(#String, len(#String) - #SplitLength - 1) end)
end
return
end
GO
/************************************************************
Function To Get columns names excluding some of them
************************************************************/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID('dbo.get_columns') IS NOT NULL
BEGIN
DROP FUNCTION dbo.get_columns
END
GO
CREATE FUNCTION dbo.get_columns
(
#table_name varchar(100),
#excluded_column_names varchar(100),
#delimter char(1)
)
RETURNS varchar(4000)
AS
BEGIN
declare #cols varchar(4000)
select #cols = COALESCE(#cols+',' ,'') + name
from sys.columns
where object_id=object_id(#table_name)
and name not in (select str_item from dbo.SplitString(#excluded_column_names,#delimter))
return #cols
END
GO
/************************************************************
Function To Get columns names excluding some of them
************************************************************/
declare #qry nvarchar(max)
set #qry = ' select ' + dbo.get_columns('TableName','Exclude_col_1,Exclude_col_2,Exclude_col_3',',')
+ ' from TableName'
+ ' where condition'
EXECUTE sp_executesql #qry
GO
Related
I need to reorder columns in the final SELECT statement in a stored procedure. Column orders needs to be fetched from another table.
I have a solution based on dynamic SQL. Is there any better way to do it? I have around 100 columns to return with millions of rows for an Excel export. Is there any other performance optimized solution other than a dynamic query?
Please find sample code below for my current solution.
IF OBJECT_ID( 'tempdb..#TempColumns') IS NOT NULL
BEGIN
DROP TABLE #TempColumns
END
IF OBJECT_ID( 'tempdb..#TempColumnsOrder') IS NOT NULL
BEGIN
DROP TABLE #TempColumnsOrder
END
CREATE TABLE #TempColumns
(
ID INT IDENTITY,
FirstName VARCHAR(MAX),
LastName VARCHAR(MAX),
Gender VARCHAR(MAX)
)
INSERT INTO #TempColumns
VALUES ('ABC', 'DEF', 'MALE'), ('PR', 'ZA', 'FEMALE'), ('ERT', 'GFG', 'MALE')
CREATE TABLE #TempColumnsOrder
(
ID INT IDENTITY,
ColumnName VARCHAR(MAX),
ColumnOrder INT
)
INSERT INTO #TempColumnsOrder
VALUES ('FirstName', 3), ('LastName', 2), ('Gender', 1)
SELECT * FROM #TempColumns
SELECT * FROM #TempColumnsOrder
DECLARE #script VARCHAR(MAX)
SELECT #script = 'SELECT '
SELECT #script = #script + ColumnName + ','
FROM #TempColumnsOrder
ORDER BY ColumnOrder
PRINT #script
SELECT #script = SUBSTRING(RTRIM(#script), 1, LEN(RTRIM(#script)) - 1)
SELECT #script = #script + ' FROM #TempColumns'
EXEC (#script)
IF OBJECT_ID( 'tempdb..#TempColumns') IS NOT NULL
BEGIN
DROP TABLE #TempColumns
END
IF OBJECT_ID( 'tempdb..#TempColumnsOrder') IS NOT NULL
BEGIN
DROP TABLE #TempColumnsOrder
END
Thanks for reply, Is there any better way in Dynamic SQL other than what i did?
You can eliminate the unsupported string concatenation you are using, and modernize and simply the code:
DROP TABLE IF EXISTS #TempColumns
DROP TABLE IF EXISTS #TempColumnsOrder
CREATE TABLE #TempColumns
(
ID INT IDENTITY,
FirstName VARCHAR(MAX),
LastName VARCHAR(MAX),
Gender VARCHAR(MAX)
)
INSERT INTO #TempColumns
Values('ABC','DEF','MALE'),('PR','ZA','FEMALE'),('ERT','GFG','MALE')
CREATE TABLE #TempColumnsOrder
(
ID INT IDENTITY,
ColumnName VARCHAR(MAX),
ColumnOrder INT
)
INSERT INTO #TempColumnsOrder
Values('FirstName',3), ('LastName',2), ('Gender',1)
SELECT * FROM #TempColumns
SELECT * FROM #TempColumnsOrder
DECLARE #script VARCHAR(MAX) = concat(
'SELECT ',
(select STRING_AGG(QUOTENAME(ColumnName),', ') WITHIN GROUP (ORDER BY ColumnOrder)
FROM #TempColumnsOrder),
' FROM #TempColumns')
print #script
EXEC (#script)
DROP TABLE IF EXISTS #TempColumns
DROP TABLE IF EXISTS #TempColumnsOrder
SELECT #script = #script + ColumnName + ',' FROM #TempColumnsOrder
ORDER BY ColumnOrder
The behavior of aggregate string concatenation with the above technique is not guaranteed. The actual behavior is plan-dependent so you may not get the desired results.
In SQL Server 2017 and Azure SQL Database, STRING_AGG is the proper method:
SELECT STRING_AGG(ColumnName, ',') WITHIN GROUP(ORDER BY ColumnOrder)
FROM #TempColumnsOrder;
In older SQL Versions like SQL Server 2012, the best method is with XML PATH():
SELECT #script = #script +
STUFF((SELECT ',' + ColumnName
FROM #TempColumnsOrder
ORDER BY ColumnOrder
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'');
See this answer for details about how the above query works.
I have two tables, Values and SpecialValues.
Values has two columns, RecordID and ValueName.
SpecialValues is a table which contains a single row, and thirty columns named SpecialValueName1, SpecialValueName2, SpecialValueName3, etc.
There are obvious database design problems with this system.
That aside, can someone explain to me how to query SpecialValues so that I can get a collection of all the values of every row from the table, and exclude them from a Select from Values?
There's probably some easy way to do this or create a View for it or something, but I think looking at this code might have broken me for the moment...
EDIT: I'd like a query to get all the individual values from every row and column of a given table (in this case the SpecialValues table) so that the query does not need to be updated the next time someone adds another column to the SpecialValues table.
This creates a #SpecialValuesColumns temporary table to store all the column names from SpecialValues.
It then uses a cursor to insert all the values from each of those columns into another temporary table #ProtectedValues.
It then uses a NOT IN query to exclude all of those values from a query to Values.
This code is bad and I feel bad for writing it, but it seems like the least-worst option open to me right now.
DECLARE #SpecialColumnsCount INT;
DECLARE #Counter INT;
DECLARE #CurrentColumnName VARCHAR(255);
DECLARE #ExecSQL VARCHAR(1024);
SET #Counter = 1;
CREATE TABLE #ProtectedValues(RecordID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, Value VARCHAR(255));
DECLARE #SpecialValuesColumns TABLE (RecordID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, ColumnName VARCHAR(255));
INSERT INTO #SpecialValuesColumns (ColumnName)
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE
TABLE_NAME = 'SpecialValues' AND
DATA_TYPE = 'varchar' AND
CHARACTER_MAXIMUM_LENGTH = 255
SELECT #SpecialColumnsCount = COUNT(*) FROM #SpecialValuesColumns
WHILE #Counter <= #SpecialColumnsCount
BEGIN
SELECT #CurrentColumnName = ColumnName FROM #SpecialValuesColumns WHERE RecordID = #Counter;
SET #ExecSQL = 'INSERT INTO #ProtectedValues (Value) SELECT ' + #CurrentColumnName + ' FROM SpecialValues'
EXEC (#ExecSQL)
SET #Counter = #Counter + 1;
END
SELECT * FROM Values WHERE ValueName NOT IN (SELECT ValueName COLLATE DATABASE_DEFAULT FROM #ProtectedValues)
DROP TABLE #ProtectedValues;
I might have misunderstood but doesn't this do it?
SELECT * FROM Values
WHERE ValueName NOT IN (
SELECT SpecialValueName1 FROM SpecialValues
UNION SELECT SpecialValueName2 FROM SpecialValues
UNION SELECT SpecialValueName3 FROM SpecialValues
etc..
)
You could of course make the subquery into a view instead.
*Edit:
This is quite ugly but should solve your problem:
First Create procedure #1
CREATE PROCEDURE [dbo].[SP1]
As
DECLARE
#Query nvarchar(MAX),
#Table nvarchar(255),
#Columns nvarchar(255)
CREATE TABLE #TempTable (Value nvarchar(255))
SET #Table = 'SpecialValues'
SELECT [COLUMN_NAME]
FROM [INFORMATION_SCHEMA].[COLUMNS]
WHERE [TABLE_NAME] = #Table
DECLARE Table_Cursor CURSOR FOR
SELECT COLUMN_NAME
FROM [INFORMATION_SCHEMA].[COLUMNS]
WHERE [TABLE_NAME] = #Table
OPEN Table_Cursor
FETCH NEXT FROM Table_Cursor INTO #Columns
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT INTO #TempTable EXEC SP2 #Columns = #Columns, #Table = #Table
FETCH NEXT FROM Table_Cursor INTO #Columns
END
CLOSE Table_Cursor
DEALLOCATE Table_Cursor
SELECT ValueName FROM Value WHERE Value NOT IN (SELECT * FROM #TempTable)
TRUNCATE TABLE #TempTable
DROP TABLE #TempTable
Then Create procedure #2
CREATE PROCEDURE [dbo].[SP2]
#Columns nvarchar(255) = '',
#Table nvarchar(255)
AS
DECLARE
#Query nvarchar(MAX)
SET #Query = 'SELECT TOP 1 CONVERT(nvarchar, ' + #Columns + ') FROM ' + #Table
EXEC (#Query)
Then lastly execute the procedure
EXEC SP1
You need to unpivot the values in specialvalues. A pretty easy way to do that is with cross apply syntax:
select sv.value
from specialvalues sv cross apply
(values(sv.SpecialValueName1), (sv.SpecialValueName2), . . .
) sv(value)
where sv.value is not null;
You can exclude these from the list using not in, not exists or a left join.
What ever way you cut it, you have to specify the columns in SpecialValues, you can do this with a long set of UNION queries, or use UNPIVOT:
select SpecialValue
from (select SpecialValueName1,SpecialValueName2,SpecialValueName3 from #SpecialValues) p
unpivot (SpecialValue FOR ROW IN (SpecialValueName1,SpecialValueName2,SpecialValueName3))
AS unpvt
You can then incorporate this into a query on Values using NOT IN
select * from [Values] where ValueName not in (
select SpecialValue
from (select SpecialValueName1,SpecialValueName2,SpecialValueName3 from #SpecialValues) p
unpivot (SpecialValue FOR ROW IN (SpecialValueName1,SpecialValueName2,SpecialValueName3))
AS unpvt
)
Let's say I have a table which contains a varchar field:
CREATE TABLE [MyTable] (
[MyId] varchar(3) NOT NULL,
.....
)
The [MyId] column contains sequential alphanum values like A1, A2... A99, B1, B2..B99, C1 and so on (up to Z99).
What I'd like to do is to extract rows from the table whose MyId field matches some specific prefixes... e.g. I'd like to fetch rows from the series A, C, P and X.
And I'd like to this with a sproc which will dynamically construct the query based on the prefix alphabets supplied in the argument.
I'm thinking about something like this...
CREATE PROCEDURE [dbo].[uspFilterMyTable]
#prefixArray varchar(max)
AS
... -- split individual characters from #prefixArray into an array
SELECT * FROM [MyTable]
WHERE
[MyId] LIKE ....
OR
[MyId] LIKE .... -- iterate all characters from #prefixArray
I think the main bulk of the stored procedure will resemble the following pseudo-code:
DECLARE #sql nvarchar(max)
-- iterate through all the characters
SET #sql = 'SELECT * FROM [MyTable] WHERE [MyId] LIKE ' + #charInTheArray + '%'
SET #sql = #sql + ' OR [MyId] LIKE ' + #nextCharInArray + '%'
EXEC (#sql)
The above proecedure will be called like this:
EXEC uspFilterMyTable("A,C,P,X")
... or perhaps like this (if it makes splitting the alphabets easier):
EXEC uspFilterMyTable("ACPX")
Any ideas? Pointers?
Update: OK, this is what I've come up with ([Split] function borrowed from Chhatrapati Sharma):
-- [MyTable] contains these rows: 'A7', 'A87', 'B16', 'C51', 'H99', 'X12'
-- the "input" parameter
DECLARE #prefixArray NVARCHAR(100)= 'H,A,C'
-- split the string into SQL wild-card patterns
DECLARE charCursor CURSOR FOR
select items + N'%' from dbo.Split(#prefixArray, ',')
OPEN charCursor;
DECLARE #pattern CHAR(2)
-- create temp table if necessary
IF NOT EXISTS(SELECT * FROM TEMPDB.SYS.TABLES WHERE NAME LIKE '#tmpTable%')
CREATE TABLE #tmpTable ([Id] VARCHAR(3) NOT NULL)
-- purge old data
DELETE FROM #tmpTable
FETCH NEXT FROM charCursor into #pattern
WHILE ##FETCH_STATUS = 0
BEGIN
--SELECT * INTO #tmpTable FROM [MyTable] WHERE [MyId] LIKE #pattern
Insert Into #tmpTable Select * FROM [MyTable] WHERE [MyId] LIKE #pattern
FETCH NEXT FROM charCursor into #pattern
END
CLOSE charCursor;
DEALLOCATE charCursor;
-- return the values
SELECT * FROM #tmpTable
It's ugly I know, but it works... any tips to improvise the code?
first you should create below function and then use this in query like this
SELECT * FROM [MyTable] WHERE [MyId] in (select items from dbo.split(#prefixArray,','))
CREATE FUNCTION [dbo].[Split](#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (items varchar(8000))
as
begin
declare #idx int
declare #slice varchar(8000)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
Here you have a nice and fast split method based on XML:
DECLARE #str NVARCHAR(100)= 'A1,B3,C4,B12,K19', #separator VARCHAR(1)= ','
DECLARE #SplitedList TABLE (code NVARCHAR(30))
DECLARE #XMLList XML
SET #XMLList=CAST('<i>'+REPLACE(#str, #separator,'</i><i>')+'</i>' AS XML)
INSERT INTO #SplitedList
SELECT x.i.value('(./text())[1]','varchar(100)')
FROM #XMLList.nodes('i') x(i)
SELECT * FROM #SplitedList
Result will be a table with the splitted values:
code
A1
B3
C4
B12
K19
From here you can continue and use this table on your procedure and join with you original table using LIKE as you propossed.
I would have suggested you to use table valued parameters to call your stored procedure. I guess you call it from .net. But EF I think will not be able to handle it, though you might check it. If not, I think the best way is to first parse the string into a temporary table, or a table value and after that join with it.
With TVP:
CREATE PROCEDURE [dbo].[uspFilterMyTable]
#prefixArray tvp_idlist readonly
as
select
t.*
from MyTable t
join #prefixArray pa on pa.id = t.myid
With a split function (of your choosing, you find many examples on the net)
CREATE PROCEDURE [dbo].[uspFilterMyTable]
#prefixArray varchar(max)
as
create #prefixArray tvp_idlist
insert into #prefixArray (id)
select id from dbo.myCustomSplit(#prefixArray,',')
select
t.*
from MyTable t
join #prefixArray pa on pa.id = t.myid
Where for both cases #prefixArray is a table variable is Id = varchar(3)
As an edit, after a little digging, it seems that with a little work EF works fine with TVPs. Check this : Entity Framework Stored Procedure Table Value Parameter. So The best thing is to send directly a table to your stored procedure, then to send a string to parse.
I want to write a SQL Server 2005 stored procedure which will select and return the user records from the user table for some userids which are passed to the stored procedure as parameter.
How to do this ?
I can pass the user ids as a string separated by comma. So that I can use the
select *
from users
where userid in (userids)
E.g. : I want to select records for id's 5,6,7,8,9
How to write the stored procedure ?
For SQL Server 2005, check out Erland Sommarskog's excellent Arrays and Lists in SQL Server 2005 article which shows some techniques how to deal with lists and arrays in SQL Server 2005 (he also has another article for SQL Server 2000).
If you could upgrade to SQL Server 2008, you can use the new feature called "table valued parameter":
First, create a user-defined table type
CREATE TYPE dbo.MyUserIDs AS TABLE (UserID INT NOT NULL)
Secondly, use that table type in your stored procedure as a parameter:
CREATE PROC proc_GetUsers #UserIDTable MyUserIDs READONLY
AS
SELECT * FROM dbo.Users
WHERE userid IN (SELECT UserID FROM #UserIDTable)
See details here.
Marc
Just use it like this will work
Create procedure sp_DoctorList
#userid varchar(100)
as
begin
exec ('select * from doctor where userid in ( '+ #userid +' )')
end
you could use dynamic sql. Pass the in statement to a Sql SP via a variable and concatenate it into a query in the SQL and execute using sp_execute sql
create procedure myproc(#clause varchar(100)) as
begin
exec sp_executesql 'select * from users where userid in ( ' + #clause +' )'
end
see my previous answer to this
this is the best source:
http://www.sommarskog.se/arrays-in-sql.html
create a split function, and use it like:
SELECT
*
FROM YourTable y
INNER JOIN dbo.splitFunction(#Parameter) s ON y.ID=s.Value
I prefer the number table approach
For this method to work, you need to do this one time table setup:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
Once the Numbers table is set up, create this function:
CREATE FUNCTION [dbo].[FN_ListToTable]
(
#SplitOn char(1) --REQUIRED, the character to split the #List string on
,#List varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN
(
----------------
--SINGLE QUERY-- --this will not return empty rows
----------------
SELECT
ListValue
FROM (SELECT
LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(#SplitOn, List2, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS List2
) AS dt
INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
WHERE SUBSTRING(List2, number, 1) = #SplitOn
) dt2
WHERE ListValue IS NOT NULL AND ListValue!=''
);
GO
You can now easily split a CSV string into a table and join on it:
select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,')
OUTPUT:
ListValue
-----------------------
1
2
3
4
5
6777
(6 row(s) affected)
Your can pass in a CSV string into a procedure and process only rows for the given IDs:
SELECT
y.*
FROM YourTable y
INNER JOIN dbo.FN_ListToTable(',',#GivenCSV) s ON y.ID=s.ListValue
Assuming T-SQL, you can use this nice function (that returns a table).
DROP FUNCTION sp_ConvertStringToTable
GO
CREATE FUNCTION sp_ConvertStringToTable(#list ntext)
RETURNS #tbl TABLE (Position INT IDENTITY(1, 1) NOT NULL,
Value INT NOT NULL) AS
BEGIN
DECLARE #pos int,
#textpos int,
#chunklen smallint,
#str nvarchar(4000),
#tmpstr nvarchar(4000),
#leftover nvarchar(4000)
SET #textpos = 1
SET #leftover = ''
WHILE #textpos <= datalength(#list) / 2
BEGIN
SET #chunklen = 4000 - datalength(#leftover) / 2
SET #tmpstr = ltrim(#leftover + substring(#list, #textpos, #chunklen))
SET #textpos = #textpos + #chunklen
SET #pos = charindex(' ', #tmpstr)
WHILE #pos > 0
BEGIN
SET #str = substring(#tmpstr, 1, #pos - 1)
INSERT #tbl (Value) VALUES(convert(int, #str))
SET #tmpstr = ltrim(substring(#tmpstr, #pos + 1, len(#tmpstr)))
SET #pos = charindex(' ', #tmpstr)
END
SET #leftover = #tmpstr
END
IF ltrim(rtrim(#leftover)) <> ''
INSERT #tbl (Value) VALUES(convert(int, #leftover))
RETURN
END
GO
In this way:
SELECT * FROM Users
WHERE userid IN
( SELECT Value FROM sp_ConvertStringToTable('1 2 3') )
You can change the stored function to work with comma separated strings instead of space separated ones.
If you don't want / can't use a stored function you can include the code of it inside the stored procedure where needed.
EDIT: this is incredibly more performant than the string concatenation.
try this this works for me
DECLARE #InClause NVARCHAR(100)
SET #InClause = 'tom,dick,harry'
DECLARE #SafeInClause NVARCHAR(100)
SET #SafeInClause = ',' + #InClause + ','
SELECT * FROM myTable WHERE PATINDEX(',' + myColumn + ',', #SafeInClause) > 0
Quick and dirty..
CREATE PROCEDURE SelectUsers (#UserIds VARCHAR(8000))
AS
SELECT * FROM Users
WHERE userid IN (SELECT CONVERT(VARCHAR(8000), value) FROM STRING_SPLIT(#UserIds, ','))
EXEC SelectUsers #UserIds = 'a1b2,c3d4,e5f6'
You can also use Find_IN_SET instead of IN. See the query below
create procedure myproc(IN in_user_ids varchar(100))
begin
select * from users where FIND_IN_SET(userid, in_user_ids);
end
I have situation that I have a table in the structure
ID, name
1, 'value1'
1, 'value2'
2, 'value3'
2, 'value4'
1, 'value5'
I wanted to show the above data in following format
id , combineName
1 ,'value1','value2', 'value5'
2 ,'value3','value4'
Is there an easy way to do this in SQL Server 2005, or will I have to run cursors to do it?
Assuming your data is in aTable:
create FUNCTION toCSV (#id int)
RETURNS varchar(100)
AS
BEGIN
DECLARE #List varchar(100)
SELECT #List = COALESCE(#List + ', ', '') +
CAST(name AS varchar(10))
FROM aTable
WHERE ID = #id
RETURN(#list)
END;
go
Then:
select distinct id, dbo.toCSV(id) from aTable
SQL 2005 has a PIVOT function that should do what you want.
http://msdn.microsoft.com/en-us/library/ms177410.aspx
You can do this using nested selects, or more easily using the pivot operator, although you have to know all of the possible values before hand.
If you want it to be dynamic, then you will need a cursor and some dynamic SQL.
Simple Example of COALESCE Function:
Created one Temp table in which i have put one 9 rows with the help of WHILE loop.
The at the Main part i have just take Column to COALESCE function.
DROP TABLE #Material
SET NOCOUNT ON
CREATE TABLE #Material
(
MaterialID INT
)
DECLARE #LoopCounter INT
DECLARE #MaxLoopCounter INT
SET #LoopCounter = 1
SET #MaxLoopCounter = 10
WHILE (#LoopCounter < #MaxLoopCounter)
BEGIN
INSERT INTO #Material (MaterialID) VALUES (#LoopCounter)
SET #LoopCounter = #LoopCounter + 1
END
/* MAIN PART */
DECLARE #MaterialID VARCHAR(100)
SELECT #MaterialID = COALESCE(#MaterialID + ',','') + CAST(MaterialID AS VARCHAR(100)) FROM #Material
PRINT 'FINAL OUTPUT: '+ #MaterialID
-- SELECT * FROM #Material
SET NOCOUNT OFF