horizontal to vertical in one field data - SQL [duplicate] - sql

This question already has answers here:
Delimited Function in SQL to Split Data between semi-colon
(2 answers)
Turning a Comma Separated string into individual rows
(16 answers)
Closed 5 years ago.
I have Input like this-
select ID,FIELD from TABLE
1| A,B,C,D
2|X,Y,Z
Output like this-
SELECT ID,FIELD from TABLE
1|A
1|B
1|C
1|D
2|X
2|Y
2|Z
Could someone please help me as how can I do it in SQL Server 2014 in an easy way ?

You can choose a string splitting function from Aaron Bertrand's Split strings the right way – or the next best way, and use it with cross apply to select the data from your table.
For this demonstration I've chosen to go with the XML string split function.
So first, create the function:
CREATE FUNCTION dbo.SplitStrings_XML
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
Then all you need to do is something like this:
SELECT ID, Item
FROM TABLE
CROSS APPLY
dbo.SplitStrings_XML(FIELD, ',')
See a live demo on rextester.
Also,you should probably read Is storing a delimited list in a database column really that bad?, where you will see a lot of reasons why the answer to this question is Absolutely yes!

You should XML With CROSS APPLY no need Explicit Function :
SELECT ID,
split.a.value('.', 'NVARCHAR(MAX)') [FIELD]
FROM
(
SELECT ID,
CAST('<M>'+REPLACE([Field], ',', '</M><M>')+'</M>' AS XML) AS String
FROM #TM
) AS a
CROSS APPLY String.nodes('/M') AS split(a);
Result :
ID FIELD
1 A
1 B
1 C
1 D
2 X
2 Y
2 Z

Related

Not able to separate delimited data in sqlserver [duplicate]

This question already has answers here:
T-SQL split string
(27 answers)
Closed 3 years ago.
I have column named Description, in that the rows are inserted along with a delimiter '-'.
I used the query to separate it. The query is mentioned below
select Description from Sheet1$
cross apply
SplitString('Description','-')
The columns have following data
Description
00000131-125
0000154-4625-4569-4568-45213
Try this below
DECLARE #Str AS TABLE ([Description] varchar(max) )
INSERT INTO #Str
SELECT '00000131-125' UNION ALL
SELECT '0000154-4625-4569-4568-45213'
SELECT Id,
LTRIM(RTRIM(Split.a.value('.','nvarchar(100)'))) AS [Description]
FROM
(
SELECT
ROW_NUMBER()OVER(ORDER BY (SELECT Null)) AS Id,
CAST('<S>'+(REPLACE([Description],'-','</S><S>')+'</S>') AS XML ) AS [Description]
FROM #Str
)AS A
CROSS APPLY [Description].nodes('S') AS Split(a)
Adding FOR XML PATH to the end of a query allows you to output the results of the query as XML elements, with the element name contained in the PATH argument.
Result
Id Description
---------------
1 00000131
1 125
2 0000154
2 4625
2 4569
2 4568
2 45213

How can I compare these two strings in SQL Server?

So I need to compare a string against another string to see if any parts of the string match. This would be useful for checking if a list of salespeople IDs against the ones that are listed to a specific GM or if falls outside of that GMs list of IDs:
ID_SP ID_GM NEEDED FIELD (overlap)
136,338,342 512,338,112 338
512,112,208 512,338,112 512,112
587,641,211 512,338,112 null
I'm struggling on how to achieve this. I'm guessing some sort of UDF?
I realize this would be much easier to have done prior to using the for XML path(''), but I'm hoping for a solution that doesn't require me to unravel the data as that will blow up the overall size of the dataset.
No, that is not how you do it. You would go back to the raw data. To get the ids in common:
select tbob.id
from t tbob join
t tmary
on tbob.id = tmary.id and tbob.manager = 'Bob' and tmary.manager = 'Mary';
Since the data set isn't two raw sources, but one 'concatenated field' and a hardcoded string field that is a list of GMIDs (same value for every row) then the correct answer (from the starting point of the question) is to use something like nodes('/M') as Split(a).
Then you get something like this:
ID_SP ID_GM
136 512,338,112
338 512,338,112
342 512,338,112
and can do something like this:
case when ID_GM not like '%'+ID_SP+'%'then 1 else 0 end as 'indicator'
From here you can aggregate back and sum the indicator field and say that if > 0 then the ID_SP exists in the list of ID_GMs
Hope this helps someone else.
-- Try This
Declare #String1 as varchar(100)='512,112,208';
Declare #String2 as varchar(100)='512,338,112';
WITH FirstStringSplit(S1) AS
(
SELECT CAST('<x>' + REPLACE(#String1,',','</x><x>') + '</x>' AS XML)
)
,SecondStringSplit(S2) AS
(
SELECT CAST('<x>' + REPLACE(#String2,',','</x><x>') + '</x>' AS XML)
)
SELECT STUFF(
(
SELECT ',' + part1.value('.','nvarchar(max)')
FROM FirstStringSplit
CROSS APPLY S1.nodes('/x') AS A(part1)
WHERE part1.value('.','nvarchar(max)') IN(SELECT B.part2.value('.','nvarchar(max)')
FROM SecondStringSplit
CROSS APPLY S2.nodes('/x') AS B(part2)
)
FOR XML PATH('')
),1,1,'')
Gordon is correct, that you should not do this. This ought do be done with the raw data. the following code will "go back to the raw data" and solve this with an easy INNER JOIN.
The CTEs will create derived tables (all the many rows you want to avoid) and check them for equality (Not using indexes! One more reason to do this in advance):
DECLARE #tbl TABLE(ID INT IDENTITY,ID_SP VARCHAR(100),ID_GM VARCHAR(100));
INSERT INTO #tbl VALUES
('136,338,342','512,338,112')
,('512,112,208','512,338,112')
,('587,641,211','512,338,112');
WITH Splitted AS
(
SELECT t.*
,CAST('<x>' + REPLACE(t.ID_SP,',','</x><x>') + '</x>' AS xml) AS PartedSP
,CAST('<x>' + REPLACE(t.ID_GM,',','</x><x>') + '</x>' AS xml) AS PartedGM
FROM #tbl AS t
)
,SetSP AS
(
SELECT Splitted.ID
,Splitted.ID_SP
,x.value('text()[1]','int') AS SP_ID
FROM Splitted
CROSS APPLY PartedSP.nodes('/x') AS A(x)
)
,SetGM AS
(
SELECT Splitted.ID
,Splitted.ID_GM
,x.value('text()[1]','int') AS GM_ID
FROM Splitted
CROSS APPLY PartedGM.nodes('/x') AS A(x)
)
,BackToYourRawData AS --Here is the point you should do this in advance!
(
SELECT SetSP.ID
,SetSP.SP_ID
,SetGM.GM_ID
FROM SetSP
INNER JOIN SetGM ON SetSP.ID=SetGM.ID
AND SetSP.SP_ID=SetGM.GM_ID
)
SELECT ID
,STUFF((
SELECT ',' + CAST(rd2.SP_ID AS VARCHAR(10))
FROM BackToYourRawData AS rd2
WHERE rd.ID=rd2.ID
ORDER BY rd2.SP_ID
FOR XML PATH('')),1,1,'') AS CommonID
FROM BackToYourRawData AS rd
GROUP BY ID;
The result
ID CommonID
1 338
2 112,512

Create function to split delimited seperated data for all records in the table [duplicate]

This question already has answers here:
Delimited Function in SQL to Split Data between semi-colon
(2 answers)
Turning a Comma Separated string into individual rows
(16 answers)
Closed 5 years ago.
I have Input like this-
select ID,FIELD from TABLE
1| A,B,C,D
2|X,Y,Z
Output like this-
SELECT ID,FIELD from TABLE
1|A
1|B
1|C
1|D
2|X
2|Y
2|Z
Could someone please help me as how can I do it in SQL Server 2014 in an easy way ?
You can choose a string splitting function from Aaron Bertrand's Split strings the right way – or the next best way, and use it with cross apply to select the data from your table.
For this demonstration I've chosen to go with the XML string split function.
So first, create the function:
CREATE FUNCTION dbo.SplitStrings_XML
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO
Then all you need to do is something like this:
SELECT ID, Item
FROM TABLE
CROSS APPLY
dbo.SplitStrings_XML(FIELD, ',')
See a live demo on rextester.
Also,you should probably read Is storing a delimited list in a database column really that bad?, where you will see a lot of reasons why the answer to this question is Absolutely yes!
You should XML With CROSS APPLY no need Explicit Function :
SELECT ID,
split.a.value('.', 'NVARCHAR(MAX)') [FIELD]
FROM
(
SELECT ID,
CAST('<M>'+REPLACE([Field], ',', '</M><M>')+'</M>' AS XML) AS String
FROM #TM
) AS a
CROSS APPLY String.nodes('/M') AS split(a);
Result :
ID FIELD
1 A
1 B
1 C
1 D
2 X
2 Y
2 Z

SQL-SERVER search array

Is that a way to search array by using SQL?
SELECT Top 1 IVDTL.YourPONo
FROM IV
INNER JOIN IVDTL
ON IV.DOCKEY = IVDTL.DOCKEY
WHERE DocNo = /*array[0]*/
Any one have idea?
For Mysql you can use FIND_IN_SET
SELECT Top 1 IVDTL.YourPONo
from IV
INNER JOIN IVDTL
ON IV.DOCKEY = IVDTL.DOCKEY
WHERE FIND_IN_SET(DocNo ,'array[0]') > 0
Update :
For SQL SERVER
You need a split string function and split the values in array to individual rows. Then it can be used in IN clause
For SQL SERVER 2016
you can use STRING_SPLIT function
SELECT Top 1 IVDTL.YourPONo
FROM IV
INNER JOIN IVDTL
ON IV.DOCKEY = IVDTL.DOCKEY
WHERE DocNo in (select value from STRING_SPLIT('array[0]',',')
For any thing less than SQL SERVER 2016
use any one of the methods from below excellent article Split strings the right way – or the next best way
Here is one way using XML
CREATE FUNCTION dbo.SplitStrings_XML
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
After creating the function use the function in your query
SELECT Top 1 IVDTL.YourPONo
FROM IV
INNER JOIN IVDTL
ON IV.DOCKEY = IVDTL.DOCKEY
WHERE DocNo in (select value from SplitStrings_XML('array[0]',',')

Separate words by group wise for each row in SQL

I have a string something like
No People,Day,side view,looking at camera,snow,mountain,tranquil scene,tranquility,Night,walking,water,Two Person,looking Down
And I have a table Group_words
Group Category
---------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------
No People,One Person,Two Person,Three Person,Four Person,five person,medium group of people,large group of people,unrecognizable person,real people People
Day,dusk,night,dawn,sunset,sunrise Weather
looking at camera,looking way,looking sideways,looking down,looking up View Angle
I want to check every comma separated word with table Group_words and find the wrong combination.
For the above string result should be : "No People,Day,side view,looking at camera,snow,mountain,tranquil scene,tranquility,walking,water"
Night is removed because Day is available in the string.
Two Person is removed because No People is available in the string.
looking Down is removed because looking at camera is available in the string.
I know its to complicated but simply I want to remove the not matching words from sting which is available into table Group_words.
Wow, you should be re-designing your tables. Anyway, here is my attempt using Jeff Moden's DelimitedSplit8k.
I believe you now have this function since I answered one of your previous questions that also uses this function.
First, you want to split your #string input into separate rows. You should also split the Group_Words table.
After that you do a LEFT JOIN to get the matching categories. Then you eliminate the invalid words.
See it in action here: SQL Fiddle
DECLARE #string VARCHAR(8000)
SET #string = 'No People,Day,side view,looking at camera,snow,mountain,tranquil scene,tranquility,Night,walking,water,Two Person,looking Down'
-- Split #string variable
DECLARE #tbl_string AS TABLE(ItemNumber INT, Item VARCHAR(8000))
INSERT INTO #tbl_string
SELECT
ItemNumber, LTRIM(RTRIM(Item))
FROM dbo.DelimitedSplit8K(#string, ',')
-- Normalize Group_Words
DECLARE #tbl_grouping AS TABLE(Category VARCHAR(20), ItemNumber INT, Item VARCHAR(8000))
INSERT INTO #tbl_grouping
SELECT
w.Category, s.ItemNumber, LTRIM(RTRIM(s.Item))
FROM Group_Words w
CROSS APPLY dbo.DelimitedSplit8K(w.[Group], ',')s
;WITH Cte AS(
SELECT
s.ItemNumber,
s.Item,
g.category,
RN = ROW_NUMBER() OVER(PARTITION BY g.Category ORDER BY s.ItemNumber)
FROM #tbl_string s
LEFT JOIN #tbl_grouping g
ON g.Item = s.Item
)
SELECT STUFF((
SELECT ',' + Item
FROM Cte
WHERE
RN = 1
OR Category IS NULL
ORDER BY ItemNumber
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),
1, 1, '')
OUTPUT:
| |
|--------------------------------------------------------------------------------------------------|
| No People,Day,side view,looking at camera,snow,mountain,tranquil scene,tranquility,walking,water |
If your #string input has more than 8000 characters, the DelimitedSplit8K will slow down. You can use other splitters instead. Here is one taken for Sir Aaron Bertrands's article.
CREATE FUNCTION dbo.SplitStrings_XML
(
#List NVARCHAR(MAX),
#Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT x = CONVERT(XML, '<i>'
+ REPLACE(#List, #Delimiter, '</i><i>')
+ '</i>').query('.')
) AS a CROSS APPLY x.nodes('i') AS y(i)
);
GO