I have a table that stores multiple values for same ID. The table looks like below:
I want to concatenate values with '&' separated.
Desired output:
My query is not producing desired output. Below is my query:
create table #temp (cid int, val1 int, val2 int, val3 int, val4 int)
insert #temp values
(1001,10,11,15,19),
(1002,15,Null,16,18),
(1003,14,18,15,NULL)
SELECT distinct t2.cid,
STUFF(( SELECT '&' + REPLACE(t1.val1,'.','') +
REPLACE(t1.val2,'.','') +
REPLACE(t1.val3,'.','') +
REPLACE(t1.val4,'.','')
FROM #temp t1
WHERE t1.cid = t2.cid
FOR XML PATH ('')
), 1, 1,'') as 'output'
FROM #temp t2
Note: I am using SQL Server 2014
For SQL Server 2017 you can use CONCAT_WS (complements to #Joakim Danielson):
SELECT cid, CONCAT_WS('&', val1, val2, val3, val4)
FROM #temp
For SQL Server 2012 you can use CONCAT:
SELECT cid, CONCAT(val1, '&', val2, '&', val3, '&', val4)
FROM #temp
For all Versions of SQL Server you can use the '+' to concatenate.
SELECT cid, val1 + '&' + val2 + '&' + val3 + '&' + val4
FROM #temp
Given that your example includes NULL and appears to be storing integers, I would recommend the following:
SELECT cid
,STUFF(COALESCE( '&' + CONVERT(VARCHAR, val1), '')
+ COALESCE( '&' + CONVERT(VARCHAR, val2), '')
+ COALESCE( '&' + CONVERT(VARCHAR, val3), '')
+ COALESCE('&' + CONVERT(VARCHAR, val4), ''), 1, 1, '')
FROM #temp
*Accepted edit to include STUFF to remove the trailing '&'
The COALESCE() will have the effect of not including NULL values in your listing, while the CONVERT to varchar will handle the Integers
You want concat_ws() functionality. You can do this in SQL Server as:
select t.cid,
stuff( (coalesce('&' + t.val1, '') +
coalesce('&' + t.val2, '') +
coalesce('&' + t.val3, '') +
coalesce('&' + t.val4, '')
), 1, 1, ''
) as vals
from #temp t;
This is the most convenient equivalent to concat_ws() that I've found in SQL Server.
If the values are integers, just cast them:
select t.cid,
stuff( (coalesce('&' + cast(t.val1 as varchar(255)), '') +
coalesce('&' + cast(t.val2 as varchar(255)), '') +
coalesce('&' + cast(t.val3 as varchar(255)), '') +
coalesce('&' + cast(t.val4 as varchar(255)), '')
), 1, 1, ''
) as vals
from #temp t;
Here is a db<>fiddle.
Use CONCAT_WS for this
SELECT cid, CONCAT_WS('&', val1, val2, val3, val4)
FROM #temp
I have a table that stores multiple values for same ID.
If CID values are not unique:
SELECT DISTINCT
t2.cid,
REPLACE(STUFF(
(
SELECT '|' + CAST(val AS VARCHAR(50))
FROM
(
SELECT cid, val1 AS val FROM #temp
UNION ALL
SELECT cid, val2 AS val FROM #temp
UNION ALL
SELECT cid, val3 AS val FROM #temp
UNION ALL
SELECT cid, val4 AS val FROM #temp
) t1
WHERE t1.cid = t2.cid
AND t1.val IS NOT NULL
FOR XML PATH('')
), 1, 1, ''), '|', '&') AS 'output'
FROM #temp t2;
Results to:
cid output
1001 10&11&15&19
1002 15&16&18
1003 14&18&15
Otherwise, CONCAT or CONCAT_WS as other members correctly suggested is more elegant solution
Related
I have a complex query that cannot be saved as a view because of the DECLARE statements at the beginning of the query.
I would like to save the results of the query into a table.
I tried to insert the following statement to surround the whole query and also only around the SET #sql and EXEC(#sql).
Both caused errors that I could not resolve.
This is the query that produces the results I need:
DECLARE #sql VARCHAR(MAX)
DECLARE #colList VARCHAR(MAX)
--create dynamic list of columns
SELECT #colList = STUFF((SELECT + ',' + QUOTENAME(colName + CAST(CAST(Billing_Order AS INTEGER) AS VARCHAR))
FROM Credible_Client_Insurance_Raw_Data
CROSS APPLY
(SELECT 1 As Ord, 'Payer_ID' ColName
UNION ALL
SELECT 2 As Ord, 'Billing_Order'
UNION ALL
SELECT 3 As Ord, 'Insurance_ID'
UNION ALL
SELECT 4 As Ord, 'Group_No'
UNION ALL
SELECT 5 As Ord, 'Copay_Fee'
UNION ALL
SELECT 6 As Ord, 'Start_Date') v
GROUP BY colName, Ord, CAST(CAST(Billing_Order AS INTEGER) AS VARCHAR)
ORDER BY CAST(CAST(Billing_Order AS INTEGER) AS VARCHAR), Ord
FOR XML PAT(''), TYPE).value('/', 'VARCHAR(MAX)'), 1, 1, '')
--unpivot columns into rows and then apply pivot
SET #sql = 'SELECT Client_ID, ' + #colList + '
FROM
(SELECT
Client_ID, ColVal,
colName + CAST(CAST(Billing_Order AS INTEGER) AS VARCHAR) ColName
FROM Credible_Client_Insurance_Raw_Data
CROSS APPLY
(
SELECT Payer_ID As ColVal, ''Payer_ID'' ColName UNION ALL
SELECT Billing_Order, ''Billing_Order'' UNION ALL
SELECT Insurance_ID, ''Insurance_ID'' UNION ALL
SELECT Group_No, ''Group_No'' UNION ALL
SELECT CAST(Copay_Fee AS VARCHAR), ''Copay_Fee'' UNION ALL
SELECT CAST(Start_Date AS VARCHAR), ''Start_Date''
) v
) A
PIVOT
(
MAX(ColVal) FOR ColName IN (' + #colList + ')
) P1 '
EXEC(#sql)
I just want to INSERT the query's result set into a permanent table Credible_Client_Insurance_Data.
Is there any way to essentially perform a
INSERT INTO Credible_Client_Insurance_Data (Client_ID, etc.)
SELECT Client_ID, etc.
FROM query_results
Or some type of data insert into the table?
IF I'm understanding correctly, don't you just need to change the value of #sql to:
SET #sql = '
INSERT INTO Credible_Client_Insurance_Data (' + #colList + ')
SELECT Client_ID, ' + #colList + '
FROM
(
SELECT Client_ID, ColVal,
colName + CAST(CAST(Billing_Order AS INTEGER) AS VARCHAR) ColName
FROM Credible_Client_Insurance_Raw_Data
CROSS APPLY
(
SELECT Payer_ID As ColVal, ''Payer_ID'' ColName UNION ALL
SELECT Billing_Order, ''Billing_Order'' UNION ALL
SELECT Insurance_ID, ''Insurance_ID'' UNION ALL
SELECT Group_No, ''Group_No'' UNION ALL
SELECT CAST(Copay_Fee AS VARCHAR), ''Copay_Fee'' UNION ALL
SELECT CAST(Start_Date AS VARCHAR), ''Start_Date''
) v
) A
PIVOT
(
MAX(ColVal) FOR ColName IN (' + #colList + ')
) P1 ;';
i have a table with a column have value seperated by semi colon.
the concern is value in the column are not fixed. it starts from 1 and end upto 80 semicolon sepaeration.
i am trying to put each individual value to seperate column
SQL SERVER 2008 code
DECLARE #Table TABLE(
Val VARCHAR(50)
)
INSERT INTO #Table (Val) SELECT '2Xcalcium; kidney' union all SELECT '3XMagnessium; liver' union all SELECT '2-ECG;3XSODIUM;DIALYSIS'
SELECT *,
CAST(LEFT(Val,CHARINDEX(';',Val)-1) AS VARCHAR) FirstValue,
CAST(RIGHT(Val,LEN(Val) - CHARINDEX(';',Val)) AS VARCHAR) SecondValue
FROM #Table
I tried the above code but this is limited to 2 semicolon only. please share your expertise.
Try it like this:
DECLARE #Table TABLE(
Val VARCHAR(50)
)
INSERT INTO #Table (Val) SELECT '2Xcalcium; kidney' union all SELECT '3XMagnessium; liver' union all SELECT '2-ECG;3XSODIUM;DIALYSIS';
;WITH Splitted AS
(
SELECT *
,CAST('<x>' + REPLACE(Val,';','</x><x>') + '</x>' AS XML) ValuesAsXML
FROM #Table
)
SELECT *
,ValuesAsXML.value('x[1]','varchar(max)') AS FirstCol
,ValuesAsXML.value('x[2]','varchar(max)') AS SecondCol
,ValuesAsXML.value('x[3]','varchar(max)') AS ThirdCol
,ValuesAsXML.value('x[4]','varchar(max)') AS FourthCol
,ValuesAsXML.value('x[5]','varchar(max)') AS FifthCol
FROM Splitted
The result
Val FirstCol SecondCol ThirdCol FourthCol FifthCol
2Xcalcium; kidney 2Xcalcium kidney NULL NULL NULL
3XMagnessium; liver 3XMagnessium liver NULL NULL NULL
2-ECG;3XSODIUM;DIALYSIS 2-ECG 3XSODIUM DIALYSIS NULL NULL
Most of the link provided extract the element into rows.
If you prefer to use your existing logic and extract the individual element into separate column, you can use multiple cascaded CROSS APPLY.
SELECT t.Val,
v1.V as V1,
v2.V as V2,
v3.V as V3
FROM #Table t
cross apply
(
select V = LEFT(t.Val, CHARINDEX(';', t.Val + ';') - 1),
Val = STUFF(t.Val, 1, CHARINDEX(';', t.Val + ';'), '')
) v1
cross apply
(
select V = LEFT(v1.Val, CHARINDEX(';', v1.Val + ';') - 1),
Val = STUFF(v1.Val, 1, CHARINDEX(';', v1.Val + ';'), '')
) v2
cross apply
(
select V = LEFT(v2.Val, CHARINDEX(';', v2.Val + ';') - 1),
Val = STUFF(v2.Val, 1, CHARINDEX(';', v2.Val + ';'), '')
) v3
From your question ,it seems that you have data in below format..This can be done easily with numbers table..
declare #string varchar(max)
set #string='s,t,a,c,k'
select substring(','+#string+',',n+1,charindex(',',','+#string+',',n+1)-n-1)
from
numbers
where n<=len(#string)
and substring(','+#string+',',n,1)=','
Output:
s
t
a
c
k
Few more Gems:
https://dba.stackexchange.com/questions/11506/why-are-numbers-tables-invaluable
http://sqlperformance.com/2012/07/t-sql-queries/split-strings
I have so many long database so I used seq_no in commas separate using more than one sequence store in single column but now I want all sequence in a single column so I am confused how to create this sql result for this.
For example:
TABLE STRUCTURE
SR_NO IS INT ,
SEQ_NO IS VARCHAR(MAX)
SR_NO SEQ_NO
---------------------------------
1 1839073,
2 1850097,1850098,
3 1850099,1850100,1850110
I need to get this result:
SEQ_NO
--------------
1839073
1850097
1850098
1850099
1850100
1850110
Thanks!
declare #t table(Id int,seq varchar(100))
insert into #t (Id,seq) values (1,'1839073,'),(2,'1839073,1850098,'),(3,'1850099,1850100,1850110 ')
;With Cte as (
SELECT A.Id,
Split.a.value('.', 'VARCHAR(100)') AS Seq
FROM
(
SELECT Id,
CAST ('<M>' + REPLACE(seq, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM #t
) AS A CROSS APPLY Data.nodes ('/M') AS Split(a) )
Select ID,Seq from Cte Where Seq > ''
Try splitting it with XML
SELECT SR_NO, t.c.value('.', 'VARCHAR(2000)') COL1
FROM (
SELECT SR_NO, x = CAST('<t>' +
REPLACE(SEQ_NO, ',', '</t><t>') + '</t>' AS XML)
FROM
(values(1,'1839073'),(2, '1850097,1850098'),
(3, '1850099,1850100,1850110')) y(SR_NO, SEQ_NO)
) a
CROSS APPLY x.nodes('/t') t(c)
Result:
SR_NO COL1
1 1839073
2 1850097
2 1850098
3 1850099
3 1850100
3 1850110
You can replace this with your table:
(values (1,'1839073'),(2, '1850097,1850098'),
(3, '1850099,1850100,1850110')) y(SR_NO, SEQ_NO)
This should do it: (Replace YourTableName with your table name)
;WITH CTE(NEW_SEQ_NO, SEQ_NO) as (
SELECT LEFT(SEQ_NO, CHARINDEX(',',SEQ_NO + ',') -1),
STUFF(SEQ_NO, 1, CHARINDEX(',',SEQ_NO + ','), '')
FROM YourTableName
WHERE SEQ_NO <> '' AND SEQ_NO IS NOT NULL
UNION all
SELECT LEFT(SEQ_NO, CHARINDEX(',',SEQ_NO + ',') -1),
STUFF(SEQ_NO, 1, CHARINDEX(',',SEQ_NO + ','), '')
FROM CTE
WHERE SEQ_NO <> '' AND SEQ_NO IS NOT NULL
)
SELECT NEW_SEQ_NO from CTE ORDER BY NEW_SEQ_NO
You can check this topic for more information:
Turning a Comma Separated string into individual rows
I have written the following query after referring Turning a Comma Separated string into individual rows
It will work for you
create table STRUCTURE(SR_NO int, SEQ_NO varchar(max))
insert STRUCTURE select 1, '1839073,'
insert STRUCTURE select 2, '1850097,1850098,'
insert STRUCTURE select 3, '1850099,1850100,1850110'
;with tmp(SR_NO, DataItem, SEQ_NO) as (
select SR_NO, LEFT(SEQ_NO, CHARINDEX(',',SEQ_NO+',')-1),
STUFF(SEQ_NO, 1, CHARINDEX(',',SEQ_NO+','), '')
from STRUCTURE
union all
select SR_NO, LEFT(SEQ_NO, CHARINDEX(',',SEQ_NO+',')-1),
STUFF(SEQ_NO, 1, CHARINDEX(',',SEQ_NO+','), '')
from tmp
where SEQ_NO > ''
)
Select DataItem as SEQ_NO from tmp order by SEQ_NO;
I have following column which contains values separated by comma. How do I convert it to a result set which gives following out put in SQL Server?
DECLARE #TBL AS TABLE
(COLUMN1 NVARCHAR(100))
INSERT INTO #TBL
SELECT 'AUD,BRL,GBP,CAD,CLP'
SELECT COLUMN1 FROM #TBL
COLUMN1
-------
AUD,BRL,GBP,CAD,CLP
Result I wanted:
COLUMN1
-------
AUD
BRL
GBP
CAD
CLP
Sadly, that's a beginners mistake. Redesign your database so that you have each of these entries in a separate table and you aren't using 'repeating groups' any more. Or at least if you're going to do anything significant with your database you need to.
create table Table1(
Id int IDENTITY(1, 1) not null -- PK
)
create table Table2
(
Id int IDENTITY(1, 1) not null, -- PK
Table1Id int not null, -- FK to Table1
Column1 varchar(50) not null
)
select *
from table1 t1
inner join table2 t2 on t2.Table1Id = t1.Id
order by t1.Id, t2.Column1
Try following
SELECT Split.T.value('.', 'VARCHAR(50)') AS column1
FROM (SELECT CAST ('<M>' +
REPLACE(column1, ',', '</M><M>') + '</M>' AS XML) AS String
FROM #TBL) AS T CROSS APPLY String.nodes ('/M') AS Split(T);
DECLARE #TBL AS TABLE
(COLUMN1 NVARCHAR(100))
INSERT INTO #TBL
SELECT 'AUD,BRL,GBP,CAD,CLP'
SELECT SUBSTRING(',' + COLUMN1 + ',', Number + 1,
CHARINDEX(',', ',' + COLUMN1 + ',', Number + 1) - Number -1)AS CaseID
FROM master..spt_values
cross join #TBL t
where type = 'P'
and Number <= LEN(',' + COLUMN1 + ',') - 1
AND SUBSTRING(',' + COLUMN1 + ',', Number, 1) = ','
I have a table like:
ID | Value
----------------
1 | One
2 | Two
3 | Three
What I need to do is create a single string from these values, in the format:
'1: One, 2: Two, 3: Three'
I know how to do this using cursors, but it will be used as a column in a view, so it's not really a performant option.
Any pointers?
WITH T(ID,Value) AS
(
SELECT 1, 'One' UNION ALL
SELECT 2, 'Two' UNION ALL
SELECT 3, 'Three'
)
SELECT STUFF(
(SELECT ', ' + CAST(ID as varchar(11)) + ': ' + Value
FROM T
FOR XML PATH (''))
, 1, 2, '')
Have a look at something like
DECLARE #Table TABLE(
ID INT,
Value VARCHAR(20)
)
INSERT INTO #Table SELECT 1,'One'
INSERT INTO #Table SELECT 2,'Two'
INSERT INTO #Table SELECT 3,'Three'
SELECT STUFF(
(
SELECT ', ' + CAST(ID AS VARCHAR(MAX)) + ': ' + Value
FROM #Table
FOR XML PATH(''), TYPE
).value('.','varchar(max)')
,1,2, ''
)
SELECT STUFF((
SELECT ' ' + CAST(ID AS VARCHAR(2)) + ': '+ Value
FROM dbo.Table
FOR XML PATH('')
), 1, 1, ''
) As concatenated_string
DECLARE #ans VARCHAR(max)
SET #ans=''
SELECT #ans = #ans + str(id)+':'+value FROM table
SELECT #ans
Change the max to 8000 if your version of SQL doesn't support it
I would simply not do this in the database if at all possible. It's not designed for formatting data in a certain way; let the calling application handle that.
In C# (assuming data is an instance of SqlDataReader):
var l = new List<string>();
while (reader.Read())
l.Add(string.Format("{0}: {1}", reader[0], reader[1]));
var s = string.Join(", ", l.ToArray());