Reputation: 39
I have an query where I get a comma seperated string as result, such as;
n,n,n,n
where n can be 0 or 1, and will always be the length of four digits.
I use CROSS APPLY STRING_SPLIT to get the result as rows. I would like to add a column to this result, and on each row have an unique string, which would be one word.
Like:
Value|String
1 | description1
0 | description2
1 | description3
1 | description4
I have googled a lot, but can't seem to find how to do this. I hope it is as easy as something like:
SELECT myResultAsRows.Value, {'a','b','c','d'} AS String
FROM table
CROSS APPLY STRING_SPLIT ...
WHERE ...
I know this seems strange, but on another forum (specific for the tool) they suggested hard-coding it... I also know it might depend on the server used, but in general, is something like this doable?
As of right now, the query is this:
SELECT tagValueRow.Value
FROM t_objectproperties tag
CROSS APPLY STRING_SPLIT(tag.Value,',') tagValueRow
WHERE tag.Object_ID = #OBJECTID# AND tag.Property = 'myTagName'
which results in
Value
1
0
1
1
for the specified #OBJECTID#.
Thank you!
edit: made the question more detailed, with example closer to reality.
Upvotes: 0
Views: 197
Reputation: 1638
I think using ROW_NUMBER()
and SUBSTRING
it can be acomplished easily.
Somethink like:
SELECT TOP 26 SUBSTRING('abcdefghijklmnopqrstuvwxyz',
ROW_NUMBER() OVER (ORDER BY sort_field), 1), *
FROM table
It has it limitation: the lenght of 'abc..' string, but with TOP
will avoid errors.
It can be done in the same way using the same approach of ROW_NUMBER
and a JOIN
:
SELECT TOP 5 T.Value, D.Label
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY Field) AS Position, tagValueRow.Value AS Value
FROM t_objectproperties tag
CROSS APPLY STRING_SPLIT(tag.Value,',') tagValueRow
WHERE tag.Object_ID = #OBJECTID# AND tag.Property = 'myTagName') T
LEFT JOIN (
VALUES
(1, 'description1'),
(2, 'description2'),
(3, 'description3'),
(4, 'description4'),
(5, 'description5')) D(Position, Label) ON T.Position=D.Position
Upvotes: 1
Reputation: 72480
If all you need is for each split row to have a value against it in no particular order, then we can cross-join a VALUES
table to it based on row-number:
SELECT tagValueRow.Value, desc.description
FROM t_objectproperties tag
CROSS APPLY (
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rn
FROM STRING_SPLIT(tag.Value,',') tagValueRow
) tagValueRow
INNER JOIN (VALUES -- or LEFT JOIN
('desciption1', 1),
('desciption2', 2),
('desciption3', 3),
('desciption4', 4),
) desc (description, rn) ON desc.rn = tagValueRow.rn
WHERE tag.Object_ID = #OBJECTID# AND tag.Property = 'myTagName'
If you may have more than 4 split avlues, but only want a description against the first 4, change the INNER JOIN
to LEFT
Upvotes: 1
Reputation: 1
CREATE TABLE Testdata ( ID INT, String VARCHAR(MAX) ) CREATE TABLE TestList ( ID INT, String VARCHAR(MAX) ) INSERT Testdata SELECT 1,'1,0,1,1' INSERT TestList SELECT 1,'a,b,c,d'
;WITH tmp(ID,DataItem, String) AS ( SELECT ID, LEFT(String, CHARINDEX(',', String + ',') - 1), STUFF(String, 1, CHARINDEX(',', String + ','), '') FROM Testdata UNION ALL SELECT ID, LEFT(String, CHARINDEX(',', String + ',') - 1), STUFF(String, 1, CHARINDEX(',', String + ','), '') FROM tmp WHERE String > '' ), tmp2(ID,DataItem, String) AS ( SELECT ID, LEFT(String, CHARINDEX(',', String + ',') - 1), STUFF(String, 1, CHARINDEX(',', String + ','), '') FROM TestList UNION ALL SELECT ID, LEFT(String, CHARINDEX(',', String + ',') - 1), STUFF(String, 1, CHARINDEX(',', String + ','), '') FROM tmp2 WHERE String > '' ) SELECT p.DataItem,q.DataItem FROM tmp AS p CROSS APPLY (SELECT * FROM tmp2) AS q --ORDER BY SomeID
DataItem | DataItem :------- | :------- 1 | a 0 | a 1 | a 1 | a 1 | b 0 | b 1 | b 1 | b 1 | c 0 | c 1 | c 1 | c 1 | d 0 | d 1 | d 1 | d
db<>fiddle here
Upvotes: 1