How to make row data comma separated in SQL? - sql-server

I am having one query which returns me following output.
(No of results not same all time, means sometimes it gives 3 category,sometimes 8 category etc..)
CategoryName
Test1
Test2
Test3
Now i want that store procedure should return me these date in comma separated format.
e.g. output string should be like: Test1,Test2,Test3
Can you please tell me how can i achieve this?

this will work for all characters in your data:
set nocount on;
declare #YourTable table (BirthDay datetime, PersonName varchar(20))
insert into #YourTable VALUES ('1-10-2010', 'Joe' )
insert into #YourTable VALUES ('2-10-2010', 'Bob <&>' )
insert into #YourTable VALUES ('2-10-2010', 'Alice')
set nocount off
--Concatenation with FOR XML and eleminating control/encoded character expansion "& < >"
SELECT
p1.BirthDay
,STUFF(
(SELECT
', ' + p2.PersonName
FROM #YourTable p2
WHERE p2.BirthDay=p1.BirthDay
ORDER BY p2.PersonName
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
) AS PersonNames
FROM #YourTable p1
GROUP BY p1.BirthDay
OUTPUT:
BirthDay PersonNames
----------------------- ------------------------
2010-01-10 00:00:00.000 Joe
2010-02-10 00:00:00.000 Alice, Bob <&>
(2 row(s) affected)

Try COALESCE or ISNULL:
DECLARE #returnValue varchar(MAX)
SELECT
#returnValue = COALESCE(#returnValue + ', ', '') + CategoryName
FROM
TableName

Have a look at something like (Full working example)
DECLARE #Table TABLE(
ID INT,
Val VARCHAR(50)
)
INSERT INTO #Table (ID,Val) SELECT 1, 'A'
INSERT INTO #Table (ID,Val) SELECT 1, 'B'
INSERT INTO #Table (ID,Val) SELECT 1, 'C'
INSERT INTO #Table (ID,Val) SELECT 2, 'B'
INSERT INTO #Table (ID,Val) SELECT 2, 'C'
--Concat
SELECT t.ID,
STUFF((
SELECT ',' + t1.Val
FROM #Table AS t1
WHERE t1.ID = t.ID
FOR XML PATH('')
), 1, 1, '')
FROM #Table t
GROUP BY t.ID
Also, you might find that Googling will provide a lot of answers.

One means:
SELECT STUFF((
SELECT ',' + CategoryName AS [text()]
FROM YourTable
FOR XML PATH('')
), 1, 1, '')
...but watch out for XML entities that will be escaped up - e.g. & => &

Just modify the KM answer in a store procedure
ALTER Procedure [dbo].[Payroll_rptAbsentReport]
#FromDate DateTime,
#ToDate DateTime,
#GFacatoryID UniqueIdentifier
As
Begin
-- Temporary table for Row data seperation
CREATE TABLE TestTable(GEmployeeGenInfoID uniqueidentifier, dtAttendDateTime varchar(max))
INSERT INTO
TestTable(GEmployeeGenInfoID, dtAttendDateTime)
SELECT
Payroll_tblAttendance.GEmployeeGenInfoID
,CONVERT(VARCHAR(max), dtAttendDateTime, 105)dtAttendDateTime
FROM Payroll_tblAttendance
INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Payroll_tblAttendance.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
WHERE Payroll_tblAttendance.DayStatusID = 0 AND EmployeeGenInfo.GFactoryID=#GFacatoryID AND Payroll_tblAttendance.dtAttendDateTime Between #FromDate and #ToDate ORDER BY dtAttendDateTime
-- Final expected output
SELECT DISTINCT
EmployeeGenInfo.StrEmpName
,EmployeeGenInfo.StrEmpID
,Attendence.CardNo
,EmployeeDesignation.StrDesignationName
,EmployeeDept.StrDepartmentName
-- Count data will be in one column
,(Select COUNT(*) From TestTable Where GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID) TotalAbsent
-- Row data set into one column seperate by coma
,substring( ( SELECT ', ' + dtAttendDateTime as [text()]
FROM TestTable
WHERE GEmployeeGenInfoID = Attendence.GEmployeeGenInfoID
FOR XML path(''), elements
), 3, 1000
) List
FROM
Payroll_tblAttendance as Attendence
INNER JOIN TestTable on TestTable.GEmployeeGenInfoID=Attendence.GEmployeeGenInfoID
INNER JOIN PIS.dbo.PIS_tblEmployeeGenInfo as EmployeeGenInfo ON Attendence.GEmployeeGenInfoID= EmployeeGenInfo.GEmployeeGenInfoID
INNER JOIN PIS.dbo.PIS_tblDesignationInfo as EmployeeDesignation ON EmployeeGenInfo.GDesignationInfoID= EmployeeDesignation.GDesignationInfoID
INNER JOIN PIS.dbo.PIS_tblDepartment as EmployeeDept ON EmployeeGenInfo.GDepartmentID= EmployeeDept.GDepartmentID
WHERE EmployeeGenInfo.GFactoryID=#GFacatoryID AND Attendence.DayStatusID = 0 AND Attendence.dtAttendDateTime Between #FromDate and #ToDate
DROP TABLE TestTable
END

Related

Concat Column Values with a separator in SQL Server

I want to concatenate column values with a separator and assign it to variable.
If column value is null, there's no need to add separator.
For example: A|B|C|D
If B is null A|C|D.
I tried with CONCAT function, but if B is null, it results in A||C|D
DECLARE #OldValue VARCHAR(8000);
SELECT #OldValue = CONCAT([FloorCode],'|',
[FloorName],'|',
[BuildingID],'|',
[HCMLocationCode],'|',
[IsActive])
FROM tblFloor_Master
WHERE FloorID = #FloorID;
#FloorID is an input parameter of SP
SELECT #OldValue = CONCAT('',
CASE WHEN [FloorCode] IS NULL THEN '' ELSE CONCAT([FloorCode],'|') END,
CASE WHEN [FloorName] IS NULL THEN '' ELSE CONCAT([FloorName],'|') END,
CASE WHEN [BuildingID] IS NULL THEN '' ELSE CONCAT([BuildingID],'|') END,
CASE WHEN [HCMLocationCode] IS NULL THEN '' ELSE CONCAT([HCMLocationCode],'|') END,
[IsActive])
FROM tblFloor_Master
WHERE FloorID = #FloorID;
You can try the following query.
create table tempTable (id int identity(1, 1),col1 char(1), col2 char(1), col3 char(1), col4 char(1))
insert into tempTable values ('A', NULL, 'C', 'D')
select * into #NewTable from(
select id, col1 as Value from tempTable where col1 is not null
union
select id, col2 as Value from tempTable where col2 is not null
union
select id, col3 as Value from tempTable where col3 is not null
union
select id, col4 as Value from tempTable where col4 is not null
)a
SELECT ID
,STUFF((SELECT '| ' + CAST(Value AS VARCHAR(10)) [text()]
FROM #NewTable
WHERE ID = t.ID
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,' ') List_Output
FROM #NewTable t
GROUP BY ID
The output is as shown below
ID List_Output
---------------
1 A| C| D
If you do not want to put space between values then you can try this
SELECT ID
,STUFF((SELECT '|' + CAST(Value AS VARCHAR(10)) [text()]
FROM #NewTable
WHERE ID = t.ID
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'') List_Output
FROM #NewTable t
GROUP BY ID
In this case the output will be
ID List_Output
---------------
1 A|C|D
You can also try the below actual query using stored procedure
create table tblFloor_Master (FloorID int identity(1, 1),
FloorCode char(1),
FloorName char(1),
BuildingID char(1),
HCMLocationCode char(1))
insert into tblFloor_Master values ('A', NULL, 'C', 'D')
GO
--To create a procedure
create proc uspGetConcateValue
#FloorId int
as
BEGIN
select * into #tblFloor_Master from(
select FloorId, FloorCode as Value from tblFloor_Master where FloorCode is not null
union
select FloorId, FloorName as Value from tblFloor_Master where FloorName is not null
union
select FloorId, BuildingID as Value from tblFloor_Master where BuildingID is not null
union
select FloorId, HCMLocationCode as Value from tblFloor_Master where HCMLocationCode is not null
)a
SELECT FloorId
,STUFF((SELECT '|' + CAST(Value AS VARCHAR(10)) [text()]
FROM #tblFloor_Master
WHERE FloorId = t.FloorId
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,1,'') List_Output
FROM #tblFloor_Master t
where FloorID = #FloorId
GROUP BY FloorId
END
Live demo here - Live Demo
Should be simple as doing replace, replace || to | then replace ||| to | since the maximum number of | is 3.
DECLARE #OldValue VARCHAR(8000);
SELECT #OldValue = replace(replace(CONCAT([FloorCode],'|',
[FloorName],'|',
[BuildingID],'|',
[HCMLocationCode],'|',
[IsActive]),'||','|'),'|||','|')
FROM tblFloor_Master
WHERE FloorID = #FloorID;
SELECT
TRIM ('|' FROM
regexp_replace(
CONCAT('','|','COLB','|','','|','COLD','|','COLE')
,'[\|]+'
,'|'
,'g'
)
)

How to insert value into a SQL Server table by getting value and column name from another table

create table T1
(
Name varchar(50),
Address varchar(50),
Tel varchar(50)
);
create table T2
(
ParamName varchar(50),
ParamValue Varchar(60),
TableName varchar(50)
);
insert into T2 values('Name', 'test', 'Member');
insert into T2 values('Address', 'testAdd', 'Member');
insert into T2 values('Tel', 'test', 'Member');
insert into T1(Select distinct ParamName from T2)
values(select ParamValue from T2 )
I'm looking for a way to do a insertion to T1 table by getting value and column name from T2 table.need to get column name from T2 table and Value to that particular column
You can use this:
INSERT INTO T2(Column1,Column2)
SELECT Column1, Column2 FROM T1
GROUP BY Column1;
You could try using a pivot query on T2 to get the names, addresses, and telephone numbers onto a single row for each table name. Then, just do an INSERT INTO ... SELECT as you were, except use the pivoted result.
INSERT INTO T1 (Name, Address, Tel)
SELECT
MAX(CASE WHEN ParamName = 'Name' THEN ParamValue END) AS Name,
MAX(CASE WHEN ParamName = 'Address' THEN ParamValue END) AS Address,
MAX(CASE WHEN ParamName = 'Tel' THEN ParamValue END) AS Tel
FROM T2
GROUP BY TableName
-- WHERE TableName IN ('Member', ...)
You can uncomment the WHERE clause if you want to restrict the insert to certain table names.
As a general comment, if you are doing this to get your data into a more normalized form, then I think it is good. But if you plan on storing your data like this long term, you might want to reconsider your table design.
Your table structure doesn't make much sense. There is no obvious logical relation between the tables. Is the second one just a buffer table?
In any case however, if you want to insert values from a table into another table you do it like that:
INSERT INTO [target_table] ([target_column_1], [target_column_2], ..., [target_column_n])
SELECT [source_column_1], [source_column_2], ..., [source_column_n]
FROM [source_table]
WHERE [conditon]
I think you are looking like..
INSERT INTO T1(Name)
SELECT DISTINCT ParamName FROM T2
DECLARE #TableName varchar(50) = 'T1'
DECLARE #ColumnName varchar(MAX)
SELECT #ColumnName= coalesce(#ColumnName + ', ', '') + a.COLUMN_NAME
from (SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
inner join T2 on TableName = TABLE_NAME
WHERE TABLE_NAME = #TableName and ParamName = COLUMN_NAME) a;
print #ColumnName
declare #ParamName varchar(MAX)
SELECT #ParamName = coalesce(#ParamName + ', ', '') + ''''+a.ParamValue+''''
from (SELECT COLUMN_NAME,ParamValue
FROM INFORMATION_SCHEMA.COLUMNS
inner join T2 on TableName = TABLE_NAME
WHERE TABLE_NAME = #TableName and ParamName = COLUMN_NAME) a;
print #ParamName
declare #QUERY nvarchar(MAX);
SET #QUERY = 'INSERT INTO T1 ('+#ColumnName+')
VALUES ('+#ParamName+')'
EXEC sp_executesql #QUERY
this is the answer what i expect ,thanks all for your help

How to use stuff on entire columns of the table:

I executed the below query and it executed well :-
SELECT table2id, stuff((select CHAR(13) + table1name from table1 where table1id=table2.table2id FOR XML PATH (''), TYPE
).value('.', 'varchar(max)')
, 1, 1, '')
from table2 where table2id=117 group by id;
But when I am using count(*) , like in below query :-
SELECT table2id, stuff((select CHAR(13) + count(*) from table1 where table1id=table2.table2id FOR XML PATH (''), TYPE
).value('.', 'varchar(max)')
, 1, 1, '')
from table2 where table2id=117 group by id;
I am getting the below error:
Msg 245, Level 16, State 1, Line 19
Conversion failed when converting the varchar value '
' to data type int.
Now how can I stuff all the columns in table1 ? could anyone help !
I want my result like below:-
table2id | table1name | table1id | table1color
------------------------------------------------------
117 | jon, jack | 117,117 | blue,red
( I am adding my sample data for table1 and table2) :-
table1:
table1id | table1name | table1color | table1city | table1animal |...(I
have 25 columns like this !)
--------------------------------------------------------------
117 | jon | blue | city1 | animal1
117 | jack | red | city2 | animal2
table2:
table2id | table2uniqueid
-------------------------
117 | asbn6383hhh3j3837
118 | kf9s8sujfu6df5d7j
This has nothing to do with stuff.
The reason you get the error is this:
count(*) returns an int. char(13) is a char. Whenever you try to do int + char SQL Server will try to implicitly convert the char to an int. Naturally, char(13) cannot be converted to an int.
What you need to to explicitly convert the count(*) to varchar:
SELECT table2id, stuff(
(
select CHAR(13) + cast(count(*) as varchar(10))
from table1
where table1id=table2.table2id
FOR XML PATH (''), TYPE).value('.', 'varchar(max)'), 1, 1, '')
from table2
where table2id=117
group by id;
Try this code it will helps you by using Dynamic Sql
Firstly i created Two physical Tables with sample data
CREATE TABLE Table1 (table1id INT , table1name Varchar(100) , table1color Varchar(100) , table1city Varchar(100) , table1animal Varchar(100))
INSERT INTO Table1
SELECT 117, 'jon' , 'blue' , 'city1' , 'animal1' UNION ALL
SELECT 117, 'jack', 'red' , 'city2' , 'animal2'
CREATE TABLE Table2( table2id INT, table2uniqueid nvarchar(1000))
INSERT INTO Table2
SELECT 117,'asbn6383hhh3j3837' Union all
SELECT 118,'kf9s8sujfu6df5d7j'
Dynamic Sql code to get the expected result
SET NOCOUNT ON
IF OBJECT_ID('Tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
CREATE TABLE #TEMP(ID INT IDENTITY ,Query nvarchar(max))
IF OBJECT_ID('Tempdb..#TEMP2') IS NOT NULL
DROP TABLE #TEMP2
CREATE TABLE #TEMP2(ID INT IDENTITY ,Query nvarchar(max))
DECLARE #MinID INT,
#MaxID INT,
#Sql nvarchar(max),
#Getcolumn nvarchar(max),
#Sql2 nvarchar(max),
#CteSql nvarchar(max),
#CteSql2 nvarchar(max),
#FullSql nvarchar(max)
DEClare #COlumn Table
(
ID INT IDENTITY,
COlumnname varchar(100)
)
INSERT into #COlumn(COlumnname)
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS Where TABLE_NAME='Table1'
SELECT #MinID=MIn(Id),#MaxID=MAX(ID)FRom #COlumn
While (#MinID <=#MaxID)
Begin
SELECT #Getcolumn=COlumnname From #COlumn WHERE ID=#MinID
SET #Sql=N' STUFF((SELECT '', ''+ CAST('+#Getcolumn +' AS VARCHAR(5))
FROM cte AS i
WHERE i.table1id=o.table1id For XML PATH ('''')),1,1,'''') AS '+#Getcolumn
INSERT INTO #TEMP(Query)
SELECT #Sql
SET #MinID=#MinID+1
END
SELECT DISTINCT #Sql2=
STUFF((SELECT ', '+ CAST(Query AS nvarchar(max)) FROM #TEMP i For Xml Path(''), type
).value('.', 'nvarchar(max)')
, 1, 2, '')
FROM #TEMP o
SET #Sql2=#Sql2 +' FRom Cte o'
SET #CteSql= 'SELECT Top 1 '+''' ;With cte
AS
(SELECT T2.table2id,''+ STUFF((SELECT '', ''+''T1.''+COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
Where TABLE_NAME=''Table1'' For XML PATH ('''')),1,1,'''') +'' From Table2 T2
LEFT JOIN Table1 T1
On T1.table1id=t2.table2id )''' +'+CHAR(13)+CHAR(10)+'+'''SELECT DISTINCT table2id,''
FROM INFORMATION_SCHEMA.COLUMNS Where TABLE_NAME=''Table1'''
INSERT INTO #TEMP2(Query)
EXECUTE(#CteSql)
SELECT #CteSql2= Query From #TEMP2
SET #FullSql=#CteSql2+#Sql2
PRINT #FullSql
EXEC(#FullSql)
SET NOCOUNT OFF
Result After Running the Query
table2id table1id table1name table1color table1city table1animal
---------------------------------------------------------------------------------------
117 117, 117 jon, jack blue, red city1, city2 anima, anima
118 NULL NULL NULL NULL NULL

Comparing multiple columns in SQL

Let's say I have 2 columns:
Column1: 'Silverado'
Column2: '1500 Vortec Max Crew Cab'
And I want to match up the record to a string that is 'Silverado 1500'
How would I go about this?
I'm running SQL Server 2014
Thank you
You could try something like this:
SELECT * FROM MyTable
WHERE Col1 + ' ' + Col2 LIKE '%Silverado 1500%'
Not exactly what you are asking for, but this is the kind of behavior I would expect for a search like this. It will give you matching results for multiple terms and how many terms were matched.
DECLARE #SearchTerms TABLE(
Term VARCHAR(200)
)
DECLARE #Table TABLE (
Col1 VARCHAR(200),
Col2 VARCHAR(200)
)
INSERT INTO #Table SELECT 'Silverado','1500 Vortec Max Crew Cab'
INSERT INTO #Table SELECT 'Honda','Accord'
DECLARE #xml as xml,#str as varchar(100),#delimiter as varchar(10)
SET #str='Silverado 1500 Crew'
SET #delimiter =' '
SET #xml = cast(('<X>'+replace(#str,#delimiter ,'</X><X>')+'</X>') as xml)
INSERT INTO #SearchTerms
SELECT N.value('.', 'varchar(10)') as value FROM #xml.nodes('X') as T(N)
SELECT t.Col1,t.Col2,count(*) [Matching Terms]
FROM #Table t
INNER JOIN #SearchTerms st on t.Col1 like '%' + st.Term + '%' OR t.Col2 like '%' + st.Term + '%'
GROUP BY t.Col1,t.Col2
ORDER BY count(*) DESC

Concatenating Value in Update

Ok, I have been banging my head against the wall for about 20 minutes and I can't seem to figure this one out. I have two tables each with a common field (ID) and what I want to do is to concatenate the values form #T2's UDValue column into #T1's UDValue column
CREATE TABLE #T1(ID INT, UDValue NVARCHAR(50))
CREATE TABLE #T2(ID INT, UDValue NVARCHAR(50))
INSERT INTO #T1(ID)
VALUES(1)
INSERT INTO #T2(ID, UDValue)
VALUES(1, 'Tom')
,(1, 'Dick')
,(1, 'Harry')
,(2, 'Chevy')
,(3, 'Apple')
,(2, 'Ford')
UPDATE #T1
SET UDValue = COALESCE(t1.UDValue, '') + t2.UDValue + ','
FROM
#T1 AS t1
INNER JOIN #T2 AS t2 ON t2.ID = t1.ID
SELECT * FROM #T1
DROP TABLE #T1
DROP TABLE #T2
So what I am looking for is to see my data like this:
ID UDValue
1, Tom,Dick,Harry
2, Chevy,Ford
3, Apple
but this is what I am getting:
ID UDValue
1 Tom,
2 Chevy,
3 Apple,
I want to avoid having to loop through each row but I don't see any alternatives.
you can use stuff with for xml path to concatenate column values
you can use a corelated sub query to get the comma separated values
Also it is not a good idea to store it as comma separated values in the database.
;with cte
as
(
select ID,
stuff((select ','+ T2.UDValue
from #T2 T2
where T2.ID = T1.ID
FOR XML PATH ('')), 1,1,'') as NewValue
from #T1 T1
)
update #T1
set UDValue = cte.NewValue
from cte
join #T1
on cte.ID = #T1.ID
select * from #T1
Concatenating Value in Update:
create table #T (Id int, Value varchar(50), primary key (Id, value));
declare #Id int;
declare #Value varchar(500);
insert into #T
( Id , Value )
values
( 1 , 'Tom' ),
( 1 , 'Dick' ),
( 1 , 'Harry' ),
( 2 , 'Chevy' ),
( 3 , 'Apple' ),
( 2 , 'Ford' );
update #T set
#Value = case when #Id is null or #Id = Id then #Value else null end,
#Value = Value = coalesce(#Value + ', ', '') + Value,
#Id = Id;
select Id, max(Value) from #T group by Id;
drop table #T;
The example works only if "primary key" is defined on the table.
More about "Quirky Update" is in Solving the Running Total and Ordinal Rank Problems
This is what I have come up with so far but I am not sure that it is the most efficient way to do this:
CREATE TABLE #T1(ID INT, UDValue NVARCHAR(50))
CREATE TABLE #T2(ID INT, UDValue NVARCHAR(50))
INSERT INTO #T1(ID)
VALUES(1)
,(2)
,(3)
INSERT INTO #T2(ID, UDValue)
VALUES(1, 'Tom')
,(1, 'Dick')
,(1, 'Harry')
,(2, 'Chevy')
,(3, 'Apple')
,(2, 'Ford')
DECLARE #id INT = 1, #UDValue NVARCHAR(MAX)
WHILE(#ID < 4)
BEGIN
SELECT #UDValue = STUFF((SELECT DISTINCT N',' + UDValue
FROM
#T2
WHERE ID = #ID
ORDER BY N',' + UDValue
FOR XML PATH(''), TYPE
).value(N'.[1]',N'nvarchar(max)'),1,1,'');
UPDATE #T1
SET UDValue = #UDValue
FROM
#T1 AS t1
WHERE
t1.ID = #ID
SELECT #ID += 1
END
SELECT * FROM #T1
DROP TABLE #T1
DROP TABLE #T2

Resources