how to add slash after every 8 characters in sql - sql

This is my query:
select
custid,
Stuff(Coalesce('' + t12, '') + Coalesce('' + t11, '') + Coalesce('' + t10, '') +
Coalesce('' + t9, '') + Coalesce('' + t8, '') + Coalesce('' + t7, '') +
Coalesce('' + t6, '') + Coalesce('' + t5, '') + Coalesce('' + t4, '') +
Coalesce('' + t3, '') + Coalesce('' + t2, '') + Coalesce('' + t1, '') +
Coalesce('' + id, ''), 1, 0, '') AS path
from
Table
This is the result I get back:
431222294701031547005760100001411000302910000718.
need to get like this:
43122229/47010315/47005760/10000141/10003029/10000718
If I use
SELECT columns, stuff(Coalesce('/' + t2, '') + Coalesce('/' + t1, '') , 1, 0, '') AS path
FROM table
the result starting like this :
/43122229/47010315/47005760/10000141/10003029/10000718.
How to fix this? Please help I've been scratching my head from hours....

if the max length of the string is know, you can use CROSS APPLY to extract every 8 characters and then concatenate together with "/" inbetween
declare #sample table
(
col varchar(100)
)
insert into #sample (col) select '12345678901234567890123'
insert into #sample (col) select '123456789012345678901234567890'
insert into #sample (col) select '12'
select s.col,
new_col = isnull(col1, '')
+ isnull('/' + col2, '')
+ isnull('/' + col3, '')
+ isnull('/' + col4, '')
+ isnull('/' + col5, '')
from #sample s
cross apply
(
select col1 = nullif(substring(col, 1, 8), '')
) p1
cross apply
(
select col2 = nullif(substring(col, 9, 8), '')
) p2
cross apply
(
select col3 = nullif(substring(col, 17, 8), '')
) p3
cross apply
(
select col4 = nullif(substring(col, 25, 8), '')
) p4
cross apply
(
select col5 = nullif(substring(col, 33, 8), '')
) p5

try this below query
SELECT columns, stuff(Coalesce('/' + t2, '') + Coalesce('/' + t1, '') , 1, 1, '') AS path
FROM table
example:
DECLARE #txt varchar(max)='/43122229/47010315/47005760/10000141/10003029/10000718'
SELECT STUFF(#txt,1,1,'') as newText
This says, starting with the first 1 character position, replace 1 character with nothing ''

Related

Only specified data from a string SQL

I have a review column in a table which has multiple strings formats like below
Example strings:
'05012:000000: :0:00000000|00647:000000: :0:00000000|00283:000000: :0:00000000|'
'05012:000000: :0:00000000|00025:000000: :0:00000000|00647:000000: :0:00000000|'
'05012:000000: :0:00000000|02095:000000: :0:00000000|00647:000000: :0:00000000|'
'05012:000000: :0:00000000|00647:000000: :0:00000000|'
'05081:023931:DF:9:20230111|00604:023931:XX:9:20230111|02470:023931:XX:9:20230111|00655:023931:XX:9:20230111|00464:023931:XX:9:20230111|02130:023931:XX:9:20230111|'
I need to get output like as below for the above strings.
The End Points are, [The End Points are "|" , ":" ]
Example strings: [output]
'05012,00647,00283'
'05012,00025,00647'
'05012,02095,00647'
'05012,00647',
'05081,00604,02470,00655,00464,02130'
I have tried with REPLACE() with SUBTRING() string functions in SQL Server, but I couldn't get the above output.
You can use STRING_SPLIT and STRING_AGG :-
https://dbfiddle.uk/db5FGFoF
Create table Temp_Tbl (Comments varchar(500));
INSERT INTO Temp_Tbl
VALUES('05012:000000: :0:00000000|00647:000000: :0:00000000|00283:000000: :0:00000000|'),
('05012:000000: :0:00000000|00025:000000: :0:00000000|00647:000000: :0:00000000|'),
('05012:000000: :0:00000000|02095:000000: :0:00000000|00647:000000: :0:00000000|')
with cte as
(select Comments, value as Value1 from Temp_Tbl cross apply STRING_SPLIT(Comments,'|')
), cte2 as
(select Comments,Value1, value as Value2 from CTE cross apply STRING_SPLIT(Value1,':')
)
select comments,STRING_AGG(Value2,',' ) from cte2
where Value2>0
group by Comments
select
coalesce(nullif(substring(col, 1, 5) + ','), ','), '') +
coalesce(nullif(substring(col, 28, 5) + ','), ','), '') +
coalesce(nullif(substring(col, 55, 5) + ','), ','), '') +
coalesce(nullif(substring(col, 82, 5) + ','), ','), '') +
coalesce(nullif(substring(col,109, 5) + ','), ','), '') +
coalesce(nullif(substring(col,136, 5) + ','), ','), '')
from T
or
select
replace(replace(replace(
substring(col, 1, 5) + ',' +
substring(col, 28, 5) + ',' +
substring(col, 55, 5) + ',' +
substring(col, 82, 5) + ',' +
substring(col,109, 5) + ',' +
substring(col,136, 5) + ','
',,,', ','), ',,', ','), ',,', ',')
from T

How to get the first letter of each word in SQL

I tried to run this query to get the initial letter of each word, and it worked for strings of 4 words, yet if the string has only two words, it duplicates the second word's initial.
select
substring(column_name, 1, 1) +
case
when 0 <> charindex(' ', column_name) + 1
then substring(column_name, charindex(' ',column_name) + 1, 1)
else ''
end +
case
when 0 <> charindex(' ', column_name, charindex(' ', column_name) + 1)
then substring(column_name, charindex(' ', column_name, charindex(' ', column_name) + 1) + 1, 1)
else ''
end +
case
when 0 <> charindex(' ', column_name, charindex(' ', column_name, charindex(' ', column_name) + 1) + 1)
then substring(column_name, charindex(' ', column_name, charindex(' ', column_name, charindex(' ', column_name) + 1) + 1) + 1, 1)
else ''
end
from table_name
You didn't specify which RDBMS you are using. This should work in SQL Server:
drop table if exists table_name
create table table_name (
column_name varchar(255)
)
insert table_name
values ('See Jane')
, ('See Jane run')
, ('See Jane run and jump over the lazy dog.')
select stuff((SELECT '' + t2.fc
from (
select left(str.value, 1) fc
, charindex(' ' + str.value + ' ', ' ' + t.column_name + ' ') idx
from string_split(t.column_name, ' ') str
) t2
order by t2.idx
FOR XML PATH('')
), 1, 0, '') as FirstChars
from table_name t
The idx column is used to order the ouptut because string_split does not promise to return the results in any particular order. Thanks to Aaron Bertrand - https://dba.stackexchange.com/questions/207274/string-split-and-ordered-results
Given the use of charindex in your question, I'm assuming you are using SQL Server. The CTE generates a tall view of your data using string_split function, with each letter on it's own row. We then select from it and group by id, and apply the string_agg function to place back into a single row.
Password guessing?
create table my_data (
id integer,
comments varchar(50)
);
insert into my_data (id, comments) values
(1, 'Thank goodness its friday'),
(2, 'I want 2 scoops of ice cream');
select * from my_data;
id
comments
1
Thank goodness its friday
2
I want 2 scoops of ice cream
with cte (id, first_char) as (
select id, substring(ss.value, 1, 1) as first_char
from my_data
cross apply string_split(comments, ' ')ss
)
select t.id,
string_agg(t.first_char, ',') as letters_delimited,
string_agg(t.first_char, '') as letters_not_delimited
from cte t
group by t.id
id
letters_delimited
letters_not_delimited
1
T,g,i,f
Tgif
2
I,w,2,s,o,i,c
Iw2soic
fiddle here
You can extend your approach with recursion
WITH cte_name AS (
select CONVERT(nvarchar(max), substring(column_name, 1, 1)) conc,
column_name n,
charindex(' ', column_name, 0) pos
from table_name
UNION ALL
select conc + substring(n, pos + 1, 1) as conc,
n,
charindex(' ', n, pos + 1) pos
from cte_name where pos > 0
)
SELECT *
FROM cte_name
where pos = 0;

How to achieve the following using functions/stored procedure in SQL Server database

I have the following table with following data as
Tab1
FutureMISBoundaryVersion CurrentMISBoundaryVersion FutureHAMBoundaryVersion CurrentHAMBoundaryVersion
2:21,5:50,4:55,7:80,9:33 2:12,5:40,4:35,7:60,9:87 2:52,5:90,4:75,7:30,9:57 2:42,5:60,4:95,7:70,9:37
This key value pair has to be split into and the value of each key has to be inserted into another table in the following fashion
FutureMIS-OAKVersion |FutureMIS-HAMVersion |FutureMIS-DURVersion | FutureMIS-BURVersion| FutureMIS-YRTVersion |DeviceMIS-OAKVersion|DeviceMIS-HAMVersion |DeviceMIS-DURVersion| DeviceMIS-BURVersion| DeviceMIS-YRTVersion
33 | 80 | 21 | 55 | 50 | 87 | 60 |12 |35 | 40
i,e: when it finds column 'FutureMISBoundaryVersion' in tab1 then its value
'2:21,5:50,4:55,7:80,9:33' will be split and its value is inserted in such a way that the corresponding value of key 2 i,e:21 will be inserted into FutureMIS-DURVersion column.
Similarly key 5's value 50 will be inserted into FutureMIS-BURVersion column and so on for other keys
when it finds column 'CurrentMISBoundaryVersion' then
'2:12,5:40,4:35,7:60,9:87' will be split and its value is inserted in such a way that the corresponding value of key 2 i,e:12 will be inserted into CurrentMIS-DURVersion column similarly key 5's 40 value will be inserted into DeviceMIS-YRTVersion column and so on for other columns of the source table.
The table structure may extend as I have shown only 4 source table column but logic for all the columns remain same
Very funky requirements to be honest.
Please note solution below will work only in SQL Server 2016+ as I'm using JSON to parse the data. However you can write your own parser, in this case code will work in almost all versions of SQL Server.
Parse function:
CREATE FUNCTION dbo.ParseIt(#Type NVARCHAR(255),#Value NVARCHAR(MAX))
RETURNS #Parsed TABLE (Code NVARCHAR(255),Value NVARCHAR(255))
AS
BEGIN
INSERT INTO #Parsed(Code,Value)
SELECT #Type + '-' + m.Code + 'Version' AS [Code],p.[1] AS [Value]
FROM (
SELECT j.[key] AS [ID],i.[key],i.value
FROM OPENJSON('["' + REPLACE(#Value,',','","') + '"]') j
CROSS APPLY OPENJSON('[' + REPLACE(j.[value],':',',') + ']') i
) a
PIVOT(MAX(a.value) FOR a.[key] IN ([0],[1])) p
INNER JOIN ( VALUES
(2,'DUR')
,(4,'BUR')
,(5,'YRT')
,(7,'HAM')
,(9,'OAK')
) m(ID, Code) ON m.ID = p.[0]
;
RETURN;
END
Initial data:
DECLARE #Table TABLE (FutureMISBoundaryVersion NVARCHAR(MAX), CurrentMISBoundaryVersion NVARCHAR(MAX),FutureHAMBoundaryVersion NVARCHAR(MAX),CurrentHAMBoundaryVersion NVARCHAR(MAX));
INSERT INTO #Table(FutureMISBoundaryVersion,CurrentMISBoundaryVersion,FutureHAMBoundaryVersion,CurrentHAMBoundaryVersion)VALUES
('2:21,5:50,4:55,7:80,9:33','2:12,5:40,4:35,7:60,9:87','2:52,5:90,4:75,7:30,9:57','2:42,5:60,4:95,7:70,9:37')
;
The code:
SELECT COALESCE(p.[FutureMIS-OAKVersion],'') AS [FutureMIS-OAKVersion]
,COALESCE(p.[FutureMIS-HAMVersion],'') AS [FutureMIS-HAMVersion]
,COALESCE(p.[FutureMIS-DURVersion],'') AS [FutureMIS-DURVersion]
,COALESCE(p.[FutureMIS-BURVersion],'') AS [FutureMIS-BURVersion]
,COALESCE(p.[FutureMIS-YRTVersion],'') AS [FutureMIS-YRTVersion]
,COALESCE(p.[DeviceMIS-OAKVersion],'') AS [DeviceMIS-OAKVersion]
,COALESCE(p.[DeviceMIS-HAMVersion],'') AS [DeviceMIS-HAMVersion]
,COALESCE(p.[DeviceMIS-DURVersion],'') AS [DeviceMIS-DURVersion]
,COALESCE(p.[DeviceMIS-BURVersion],'') AS [DeviceMIS-BURVersion]
,COALESCE(p.[DeviceMIS-YRTVersion],'') AS [DeviceMIS-YRTVersion]
FROM (
SELECT f.Code,f.Value FROM #Table t CROSS APPLY dbo.ParseIt('FutureMIS',t.FutureMISBoundaryVersion) f
UNION ALL
SELECT f.Code,f.Value FROM #Table t CROSS APPLY dbo.ParseIt('DeviceMIS',t.CurrentMISBoundaryVersion) f
) a
PIVOT(MAX(a.Value) FOR a.Code IN ([DeviceMIS-BURVersion],[DeviceMIS-DURVersion],[DeviceMIS-HAMVersion],[DeviceMIS-OAKVersion]
,[DeviceMIS-YRTVersion],[FutureMIS-BURVersion],[FutureMIS-DURVersion],[FutureMIS-HAMVersion],[FutureMIS-OAKVersion]
,[FutureMIS-YRTVersion])) p
;
The following query will parse the comma separated string 2:21,5:50,4:55,7:80,9:33 into individual component 2:21, 5:30 etc. From there you can use similar method to extract bb from aa:bb.
Since the key-value pair is in format aa:bb, you can use datepart(hour, 'aa:bb') and datepart(minute, 'aa:bb') to extract aa and bb
; with
Tab1 as
(
select val = '2:21,5:50,4:55,7:80,9:33'
)
select t.*, k1.k, k2.k, k3.k, k4.k, k5.k
from Tab1 t
cross apply
(
select i = charindex(',', t.val),
k = substring(t.val, 1, charindex(',', t.val + ',', 1) - 1)
) k1
cross apply
(
select i = charindex(',', t.val, k1.i + 1),
k = substring(t.val, k1.i + 1, charindex(',', t.val + ',', k1.i + 1) - k1.i - 1)
) k2
cross apply
(
select i = charindex(',', t.val, k2.i + 1),
k = substring(t.val, k2.i + 1, charindex(',', t.val + ',', k2.i + 1) - k2.i - 1)
) k3
cross apply
(
select i = charindex(',', t.val, k3.i + 1),
k = substring(t.val, k3.i + 1, charindex(',', t.val + ',', k3.i + 1) - k3.i - 1)
) k4
cross apply
(
select i = charindex(',', t.val, k4.i + 1),
k = substring(t.val, k4.i + 1, charindex(',', t.val + ',', k4.i + 1) - k4.i - 1)
) k5
This is a pain in SQL Server. You can do this with recursive CTEs:
with cte as (
select convert(varchar(max), left(FutureMISBoundaryVersion, charindex(',', FutureMISBoundaryVersion) - 1)) as FutureMISBoundaryVersion,
convert(varchar(max), left(CurrentMISBoundaryVersion, charindex(',', CurrentMISBoundaryVersion) - 1)) as CurrentMISBoundaryVersion,
convert(varchar(max), left(FutureHAMBoundaryVersion, charindex(',', FutureHAMBoundaryVersion) - 1)) as FutureHAMBoundaryVersion,
convert(varchar(max), left(CurrentHAMBoundaryVersion, charindex(',', FutureMISBoundaryVersion) - 1)) as CurrentHAMBoundaryVersion,
stuff(FutureMISBoundaryVersion, 1, charindex(',', FutureMISBoundaryVersion), '') + ',' as FutureMISBoundaryVersion_rest,
stuff(CurrentMISBoundaryVersion, 1, charindex(',', CurrentMISBoundaryVersion), '') + ',' as CurrentMISBoundaryVersion_rest,
stuff(FutureHAMBoundaryVersion, 1, charindex(',', FutureHAMBoundaryVersion), '') + ',' as FutureHAMBoundaryVersion_rest,
stuff(CurrentHAMBoundaryVersion, 1, charindex(',', CurrentHAMBoundaryVersion), '') + ',' as CurrentHAMBoundaryVersion_rest,
1 as lev
from t
union all
select convert(varchar(max), left(FutureMISBoundaryVersion_rest, charindex(',', FutureMISBoundaryVersion_rest) - 1)) as FutureMISBoundaryVersion,
convert(varchar(max), left(CurrentMISBoundaryVersion_rest, charindex(',', CurrentMISBoundaryVersion_rest) - 1)) as CurrentMISBoundaryVersion,
convert(varchar(max), left(FutureHAMBoundaryVersion_rest, charindex(',', FutureHAMBoundaryVersion_rest) - 1)) as FutureHAMBoundaryVersion,
convert(varchar(max), left(CurrentHAMBoundaryVersion_rest, charindex(',', CurrentHAMBoundaryVersion_rest) - 1)) as CurrentHAMBoundaryVersion,
stuff(FutureMISBoundaryVersion_rest, 1, charindex(',', FutureMISBoundaryVersion_rest), '') as FutureMISBoundaryVersion_rest,
stuff(CurrentMISBoundaryVersion_rest, 1, charindex(',', CurrentMISBoundaryVersion_rest), '') as CurrentMISBoundaryVersion_rest,
stuff(FutureHAMBoundaryVersion_rest, 1, charindex(',', FutureHAMBoundaryVersion_rest), '') as FutureHAMBoundaryVersion_rest,
stuff(CurrentHAMBoundaryVersion_rest, 1, charindex(',', CurrentHAMBoundaryVersion_rest), '') as CurrentHAMBoundaryVersion_rest,
lev + 1
from cte
where FutureMISBoundaryVersion_rest like '%,%'
)
select FutureMISBoundaryVersion, CurrentMISBoundaryVersion, FutureHAMBoundaryVersion, CurrentHAMBoundaryVersion, lev
from cte;
Here is a db<>fiddle.

Finding matching values in a field, that a seperated by spaces

In SQL Server I have a field that has delimited data (by space) in it.
E.g.
recid| Delimited data field
1| 1 2 3 4 5
2| 1 2 3 3 5
3| 1 1 1 1 1
I need to loop through all the records in the DB and interrogate the delimited data field and compare the third and fourth parts of data against each other and if they match, return the recid and the whole delimited field.
So from my example records 2 and 3 have matching data parts, so it would return:-
2|1 2 3 3 5
3|1 1 1 1 1
Because 3 3 matches, as does 1 1.
Thanks.
If it is always 1 digit and same format, you can try like following.
select * from #table
where SUBSTRING([data], 5, 1) = SUBSTRING([data], 7, 1)
If not (Numbers are not single digit), you can try like following.
;WITH cte
AS (SELECT F1.recid,
F1.[data],
O.splitdata,
Row_number()
OVER(
partition BY recid
ORDER BY (SELECT 1)) rn
FROM (SELECT *,
Cast('<X>' + Replace(F.data, ' ', '</X><X>') + '</X>' AS
XML)
AS
xmlfilter
FROM #table F)F1
CROSS apply (SELECT fdata.d.value('.', 'varchar(50)') AS
splitdata
FROM f1.xmlfilter.nodes('X') AS fdata(d)) O)
SELECT c1.recid,
c1.data
FROM cte c1
INNER JOIN cte c2
ON c1.recid = c2.recid
AND c1.rn = 3
AND c2.rn = 4
AND c1.splitdata = c2.splitdata
GROUP BY c1.recid,
c1.data
Online Demo
Need to split the data, give the row number and then compare.
Schema:
SELECT * INTO #TAB FROM (
SELECT 1, '1 2 3 4 5' UNION ALL
SELECT 2, '1 2 3 3 5' UNION ALL
SELECT 3, '1 1 1 1 1'
)A (recid , Delimited_data_field)
Solution :
;WITH CTE
AS (
SELECT recid
,Delimited_data_field
,ROW_NUMBER() OVER (PARTITION BY recid ORDER BY (SELECT 1)) RNO
,splt.X.value('.', 'INT') VAL
FROM (
SELECT recid
,Delimited_data_field
,CAST('<M>' + REPLACE(Delimited_data_field, ' ', '</M><M>') + '</M>' AS XML) DATA
FROM #TAB
) A
CROSS APPLY A.DATA.nodes('/M') splt(x)
)
SELECT C.recid
,C2.Delimited_data_field
FROM CTE C
INNER JOIN CTE C2 ON C.recid = C2.recid AND C.RNO = 3 AND C2.RNO = 4
AND C.VAL = C2.VAL
Result :
recid Delimited_data_field
2 1 2 3 3 5
3 1 1 1 1 1
Your question has two parts, find nth split and then compare. Your first approach should be to break the problem until you find built in functions that can do the job.
here is one method inner query return result after split and outer compares:
SELECT recid,Delimited from (
SELECT recid,Delimited, SUBSTRING(Delimited,
charindex(' ', Delimited, (charindex(' ', Delimited, 1))+2)+1,1)
third, SUBSTRING(Delimited, charindex(' ',Delimited,
(charindex(' ', Delimited, 1))+3)+1,1)
fourth FROM YourTable) tr
WHERE third = fourth
See simple substring and charindex can do the job.
Here is one more solution to that.
I tweaked the split function in this link (T-SQL: Opposite to string concatenation - how to split string into multiple records) a bit to make it usefule in your scenario.
Here is the function.
CREATE FUNCTION dbo.SplitAndGetNumberAt (#sep char(1), #s varchar(512), #pos int)
RETURNS INT
BEGIN
declare #val as varchar(10);
WITH Pieces(pn, start, stop) AS (
SELECT 1, 1, CHARINDEX(#sep, #s)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(#sep, #s, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT #val = SUBSTRING(#s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END)
FROM Pieces where pn = #pos;
RETURN #val
END
Now you can use this function to get 3rd and 4th position of numbers and compare easily.
select recid, deldata
from so1
where dbo.SplitAndGetNumberAt (' ', deldata, 3) = dbo.SplitAndGetNumberAt (' ', deldata, 4)
Hope it will help.
If you have SQL Server 2016 or higher, you may try one approach using OPENJSON() to split your input data. The important part here is the fact, that when OPENJSON parses a JSON array the indexes of the elements in the JSON text are returned as keys (0-based).
Input:
CREATE TABLE #Table (
RecId int,
Data varchar(max)
)
INSERT INTO #Table
(RecId, Data)
VALUES
(1, '1 2 3 4 5'),
(2, '1 2 3 3 5'),
(3, '1 1 1 1 1')
Statement:
SELECT
t.RecId,
t.Data
FROM #Table t
CROSS APPLY (SELECT [value] FROM OPENJSON('["' + REPLACE(t.Data,' ','","') + '"]') WHERE [key] = 2) j3
CROSS APPLY (SELECT [value] FROM OPENJSON('["' + REPLACE(t.Data,' ','","') + '"]') WHERE [key] = 3) j4
WHERE j3.[value] = j4.[value]
Output:
RecId Data
2 1 2 3 3 5
3 1 1 1 1 1
Just for fun, sort of crazy coding:
DECLARE #Table Table (
recid INT,
DelimitedDataField VARCHAR(32)
)
INSERT #Table (recid, DelimitedDataField)
VALUES
(1, '1 2 3 4 5'),
(2, '1 2 3 3 5'),
(3, '1 1 1 1 1')
SELECT *
FROM #Table
WHERE
SUBSTRING (
STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
''),
1,
CHARINDEX(' ', STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
'')
)
) =
SUBSTRING (
STUFF(
STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
''),
1,
CHARINDEX(' ', STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
'')
),
''
),
1,
CHARINDEX(' ', STUFF(
STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
''),
1,
CHARINDEX(' ', STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
'')
),
''
))
)
AND SUBSTRING (
STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
''),
1,
CHARINDEX(' ', STUFF(
STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'),
''
),
1,
CHARINDEX(' ', STUFF(
DelimitedDataField + ' - - -',
1,
CHARINDEX(' ', DelimitedDataField + ' - - -'), '')
),
'')
)
) <>'-'

Stuff query in SQL

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