fetch comma separated value in SQL query - sql

Please check below table
Code Name
-----------
001 A
001 B
My query is
Select Code,Name from TableA
But I need records like
Code Name
------------
001 A,B
How can I do that?

Unlike MySQL, SQL Server doesn't have a built-in function for this but you can still simulate it by using CROSS APPLY and FOR XML PATH('')
SELECT a.Code,
SUBSTRING(d.[Name],1, LEN(d.[Name]) - 1) AddressList
FROM
(
SELECT DISTINCT Code
FROM TableA
) a
CROSS APPLY
(
SELECT [Name] + ', '
FROM TableA AS B
WHERE A.[Code] = B.[Code]
FOR XML PATH('')
) D ([Name]) ;
SQLFiddle Demo

You could use COALESCE. The following sample turns this
Hello
World
It's
Me
into this
Hello, World, It's, Me
DECLARE #test NVARCHAR(2000)
SELECT #test = COALESCE(#test + ', ', '') + Field FROM Sampletable WHERE … AND Field IS NOT NULL
SELECT #test
You should be able to adapt this to your sample.

Related

Combine multiple rows into one by coalescing one column's value as CSV from two tables

I'll divide this into three parts:
What I have:
I have two tables Table1 and Table2.
Table1
ObjectName
Status
A
Active
C
Active
Table2
ParentObjectType
ChildObjectType
X
A
Y
C
Z
A
M
C
What I want:
I want to write a stored procedure that gives a result that looks something like this:
ObjectName
Status
ParentObjectName
A
Active
X, Z
C
Active
Y, M
What I have tried: I tried using the STUFF function and I'm getting a weird result.
Here's the query:
SELECT
ObjectName,
Status,
STUFF((SELECT '; ' + table2.ParentObjectType
FROM table1
INNER JOIN table2 ON table1.[ObjectName] = table2.[ChildObjectType]
FOR XML PATH('')), 1, 1, '') [ParentObjectName]
FROM
table1
Output
ObjectName
Status
ParentObjectName
A
Active
X, Z, Y, M
C
Active
X, Z, Y, M
Any help here is highly appreciated as I'm light handed on SQL and this is driving me nuts!
Demo: Fiddle
You are missing WHERE condition in your Subquery for a parent table.
Also I assume this is a typo. In Table2 you have column ChildObjectType but in your link you are linking over ˛table2.[ChildObjectName]
SELECT
ObjectName,
Status,
STUFF((SELECT '; ' + table2.ParentObjectType
FROM table1
INNER JOIN table2 ON table1.[ObjectName] = table2.[ChildObjectName]
WHERE Table1.ObjectName = src.ObjectName
FOR XML PATH('')), 1, 1, '') [ParentObjectName]
FROM
table1 src
Note: You can use STRING_AGG starting from SQL Server 2017 (14.x) and later
This helped me realize I didn't have this saved in my snippets, thanks! Being careful thatFOR XML PATH will return XML Encoded text, so "&" becomes "&", see below for an example that shows you can add , TYPE to your FOR XML statement; This returns an xml datatype, that you can query the text out of with value('.',....
I personally tend to favor subqueries below the FROM, so this also shows an alternative style for joining the data, via a WHERE clause inside the APPLY refernce:
DECLARE #tt1 TABLE ( ObjectName VARCHAR(10), StatusValue VARCHAR(20) )
INSERT INTO #tt1
SELECT 'A','Active'
UNION ALL SELECT 'C','Active'
UNION ALL SELECT 'D&E','Active'
DECLARE #tt2 TABLE ( A VARCHAR(100), B VARCHAR(100) )
INSERT INTO #tt2 SELECT 'X','A'
INSERT INTO #tt2 SELECT 'Y','C'
INSERT INTO #tt2 SELECT 'Z','A'
INSERT INTO #tt2 SELECT 'M','C'
INSERT INTO #tt2 SELECT 'E&F','D&E' --sample "&" that should NOT render "&"
INSERT INTO #tt2 SELECT '"G"','D&E'
INSERT INTO #tt2 SELECT 'F>G','C' --sample ">" that should NOT render ">"
SELECT
tt1.*,
f1.*
FROM
(SELECT ObjectName,StatusValue FROM #tt1) tt1
OUTER APPLY (SELECT
COALESCE(STUFF(
(SELECT ',' + CAST(tt2.A AS VARCHAR(10))
FROM
#tt2 tt2 WHERE tt2.B = tt1.ObjectName FOR XML PATH(''), TYPE ).value('.','nvarchar(max)'), 1,1,''),'') [csv1] ) f1
I'm assuming that you are on a SQL server version that does not have string aggregating functions?

How to Compare Two Columns and Display the difference in a new Column - SQL Server

I want to compare two columns of type nvarchar and show the output in a new column, is there a way to achieve this in Microsoft SQL Server?
Example:
COL1 COL2
-------------------- -----------------------------------
This is my test case This is not my test Case, leave me alone
OUTPUT
---------------------
not, leave me alone
The solution below works one way: col1 words are removed from col2.
Sample data
create table test
(
id int,
col1 nvarchar(max),
col2 nvarchar(max)
);
insert into test (id, col1, col2) values
(1, 'This is my test case', 'This is not my test Case, leave me alone');
Solution
with cte as
(
select t.id,
replace(s.value, ',', '') as word
from test t
cross apply string_split(t.col2, ' ') s
except
select t.id,
replace(s.value, ',', '')
from test t
cross apply string_split(t.col1, ' ') s
)
select string_agg(c.word, ' ') as result
from cte c
group by c.id;
Result
result
------------------
alone leave me not
Fiddle to see things in action with intermediate results.
New solution
Perhaps this version does not look so clean, but it should preserve the word order...
with cte as
(
select t.id,
row_number() over(order by (select null)) as sort,
replace(s.value, ',', '') as word
from test t
cross apply string_split(t.col2, ' ') s
where not exists ( select 'x'
from test t
cross apply string_split(t.col1, ' ') s2
where replace(s2.value, ',', '') = replace(s.value, ',', '') )
)
select string_agg(c.word, ' ') within group (order by c.sort) as result
from cte c
group by c.id;
New result
result
------------------
not leave me alone
New fiddle.

SQL Pivot Convert Null to 0 [duplicate]

I tried to convert the (null) values with 0 (zeros) output in PIVOT function but have no success.
Below is the table and the syntax I've tried:
SELECT
CLASS,
[AZ],
[CA],
[TX]
FROM #TEMP
PIVOT (SUM(DATA)
FOR STATE IN ([AZ], [CA], [TX])) AS PVT
ORDER BY CLASS
CLASS AZ CA TX
RICE 10 4 (null)
COIN 30 3 2
VEGIE (null) (null) 9
I tried to use the ISNULL but did not work.
PIVOT SUM(ISNULL(DATA,0)) AS QTY
What syntax do I need to use?
SELECT CLASS,
isnull([AZ],0),
isnull([CA],0),
isnull([TX],0)
FROM #TEMP
PIVOT (SUM(DATA)
FOR STATE IN ([AZ], [CA], [TX])) AS PVT
ORDER BY CLASS
If you have a situation where you are using dynamic columns in your pivot statement you could use the following:
DECLARE #cols NVARCHAR(MAX)
DECLARE #colsWithNoNulls NVARCHAR(MAX)
DECLARE #query NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(Name)
FROM Hospital
WHERE Active = 1 AND StateId IS NOT NULL
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #colsWithNoNulls = STUFF(
(
SELECT distinct ',ISNULL(' + QUOTENAME(Name) + ', ''No'') ' + QUOTENAME(Name)
FROM Hospital
WHERE Active = 1 AND StateId IS NOT NULL
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
EXEC ('
SELECT Clinician, ' + #colsWithNoNulls + '
FROM
(
SELECT DISTINCT p.FullName AS Clinician, h.Name, CASE WHEN phl.personhospitalloginid IS NOT NULL THEN ''Yes'' ELSE ''No'' END AS HasLogin
FROM Person p
INNER JOIN personlicense pl ON pl.personid = p.personid
INNER JOIN LicenseType lt on lt.licensetypeid = pl.licensetypeid
INNER JOIN licensetypegroup ltg ON ltg.licensetypegroupid = lt.licensetypegroupid
INNER JOIN Hospital h ON h.StateId = pl.StateId
LEFT JOIN PersonHospitalLogin phl ON phl.personid = p.personid AND phl.HospitalId = h.hospitalid
WHERE ltg.Name = ''RN'' AND
pl.licenseactivestatusid = 2 AND
h.Active = 1 AND
h.StateId IS NOT NULL
) AS Results
PIVOT
(
MAX(HasLogin)
FOR Name IN (' + #cols + ')
) p
')
You cannot place the IsNull() until after the data is selected so you will place the IsNull() around the final value in the SELECT:
SELECT CLASS,
IsNull([AZ], 0) as [AZ],
IsNull([CA], 0) as [CA],
IsNull([TX], 0) as [TX]
FROM #TEMP
PIVOT
(
SUM(DATA)
FOR STATE IN ([AZ], [CA], [TX])
) AS PVT
ORDER BY CLASS
Sometimes it's better to think like a parser, like T-SQL parser. While executing the statement, parser does not have any value in Pivot section and you can't have any check expression in that section. By the way, you can simply use this:
SELECT CLASS
, IsNull([AZ], 0)
, IsNull([CA], 0)
, IsNull([TX], 0)
FROM #TEMP
PIVOT (
SUM(DATA)
FOR STATE IN (
[AZ]
, [CA]
, [TX]
)
) AS PVT
ORDER BY CLASS
You have to account for all values in the pivot set. you can accomplish this using a cartesian product.
select pivoted.*
from (
select cartesian.key1, cartesian.key2, isnull(relationship.[value],'nullvalue') as [value]
from (
select k1.key1, k2.key2
from ( select distinct key1 from relationship) k1
,( select distinct key2 from relationship) k2
) cartesian
left outer join relationship on relationship.key1 = cartesian.key1 and relationship.key2 = carterisan.key2
) data
pivot (
max(data.value) for ([key2_v1], [key2_v2], [key2_v3], ...)
) pivoted
To modify the results under pivot, you can put the columns in the selected fields and then modify them accordingly. May be you can use DECODE for the columns you have built using pivot function.
Kranti A
I have encountered a similar problem. The root cause is that (use your scenario for my case), in the #temp table, there is no record for:
a. CLASS=RICE and STATE=TX
b. CLASS=VEGIE and (STATE=AZ or STATE=CA)
So, when MSSQL does pivot for no record, MSSQL always shows NULL for MAX, SUM, ... (aggregate functions).
None of above solutions (IsNull([AZ], 0)) works for me, but I do get ideas from these solutions.
Sorry, it really depends on the #TEMP table. I can only provide some suggestions.
Make sure #TEMP table have records for below condition, even Data is null.
a. CLASS=RICE and STATE=TX
b. CLASS=VEGIE and (STATE=AZ or STATE=CA)
You may need to use cartesian product: select A.*, B.* from A, B
In the select query for #temp, if you need to join any table with WHERE, then would better put where inside another sub select query. (Goal is 1.)
Use isnull(DATA, 0) in #TEMP table.
Before pivot, make sure you have achieved Goal 1.
I can't give an answer to the original question, since there is no enough info for #temp table. I have pasted my code as example here.
SELECT * FROM (
SELECT eeee.id as enterprise_id
, eeee.name AS enterprise_name
, eeee.indicator_name
, CONVERT(varchar(12) , isnull(eid.[date],'2019-12-01') , 23) AS data_date
, isnull(eid.value,0) AS indicator_value
FROM (select ei.id as indicator_id, ei.name as indicator_name, e.* FROM tbl_enterprise_indicator ei, tbl_enterprise e) eeee
LEFT JOIN (select * from tbl_enterprise_indicator_data WHERE [date]='2020-01-01') eid
ON eeee.id = eid.enterprise_id and eeee.indicator_id = enterprise_indicator_id
) AS P
PIVOT
(
SUM(P.indicator_value) FOR P.indicator_name IN(TX,CA)
) AS T

Combine two rows into one row. like average function but instead it will concat

I'm using SQL Server 2000.
What I want to do is like average function but instead it will concat.
Is there a way that I can do that?
For example I have this data.
Name | Score
Name1 | 50
Name1 | 70
and the output should be like this.
Name | Score
Name1 | 50,70
Use below query for your reference.
Query
Select main.doctorID,
Left(Main.submain,Len(Main.submain)-1) As 'Title'
From
(
Select distinct ST2.doctorID,
(
Select convert(varchar,ST1.encounterid) + ',' AS [text()]
From dbo.enc ST1
Where ST1.doctorID = ST2.doctorID
ORDER BY ST1.doctorID
For XML PATH ('')
) submain
From dbo.enc ST2
) [Main]
If you can use CLR, look at this example :
https://msdn.microsoft.com/en-us/library/ms165055%28v=vs.90%29.aspx
It provides a custom aggregate that concatenates values, which results in very clean code.
You can do it by this simple query.
Select Name, (Select SUBSTRING((SELECT ', '+Score from TableName for XML
Path('')) ,2,8000)) from TableName
You will have result like
ColumnName | val1, val2, ....
check this.
INSERT INTO #T VALUES
('name1', 50),
('name1', 70)
SELECT * FROM #T
Select name ,
STUFF((SELECT ',' + cast( score as varchar(50)) FROM #T WHERE (
name=Result.name) FOR XML PATH ('')),1,1,'') AS BATCHNOLIST
From #T AS Result
GROUP BY name
Can I Comma Delimit Multiple Rows Into One Column?
Query
SELECT Name,
(SELECT SUBSTRING((SELECT ', '+CAST(Score AS VARCHAR(MAX)) FROM my_table FOR XML Path('')) ,2,1000)) AS Score
FROM my_table
GROUP BY name;
Fiddle for reference
If you are using SQL Server 2000, then try to create a function as follows.
CREATE TABLE my_table(name VARCHAR(50),score INT);
INSERT INTO my_table VALUES('Name1',50);
INSERT INTO my_table VALUES('Name1',70);
Function
CREATE FUNCTION commaseparated(#name VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #score VARCHAR(MAX)
SELECT #score = COALESCE(#score + ', ', '') + CAST(score AS VARCHAR(MAX))
FROM my_table
WHERE name = #name
RETURN #score
END
SELECT
name,
score = dbo.commaseparated(name)
FROM my_table
GROUP BY name;

Comma separated values in one column - SQL SERVER

Customer Table
--------------
ID Name
1 James
2 Peter
Order Table
---------------
OrderId CustId
100 1
101 1
102 2
How can I write a query that returns something like this
ID,Name,ListofOrders
1,James,"100,101"
2,Peter,"102"
In Sybase I had a function called LIST which I could use but I dont find a similar function in SQL SERVER
Please try:
select ID, [Name],
(select OrderID+',' from OrderTable where CustID=ID
group by OrderID for xml path('')) AS ListOfOrders
From CustomerTable
Create a User Defined Function as shown below
CREATE FUNCTION [dbo].[CommaSeperatedOrderIDs](#CustId INT) returns varchar(Max)
AS
BEGIN
DECLARE #CommaSeperatedValues VARCHAR(MAX)
SELECT #CommaSeperatedValues = COALESCE(#CommaSeperatedValues+',' , '') + OrderID
FROM OrderTable WHERE CustId = #CustId
RETURN #CommaSeperatedValues
END
And then,
select ID, [Name], ([dbo].[CommaSeperatedOrderIDs](ID)) AS ListofOrders
From CustomerTable
Adding full details from Sheikh Haris' link.
Given this table:
To get output like:
Use the following SQL:
SELECT field1,
Substring(convert(varchar(100),
(
SELECT (', ' + field2)
FROM #test t2
WHERE t1.field1 = t2.field1
ORDER BY field1, field2
FOR XML PATH( '' )
)), 3, 1000 )
FROM #test t1
GROUP BY field1
I added a convert function to the substring so that the WIDEMEMO field would be displayed (SQL Server)
A very simple and handy solution given on the link below.
http://tejasnshah.wordpress.com/2009/02/28/sql-server-get-column-values-as-comma-seperated-list-using-xml-path-instead-of-udfs-using-sql-coalesce/
The SQL query written on that link is in an image ...so i couldn't copy it here.