Converting a single comma separated row into multiple rows - sql

I am trying to convert a single comma-separated row (column) into multiple rows by using this query:
SELECT
Split.a.value('.', 'VARCHAR(max)') AS String
FROM
(SELECT
CAST ('<M>' + REPLACE(cast([csvdata] as Varchar(max)), ',', '</M><M>') + '</M>' AS XML) AS String
FROM
tboutbound
WHERE
id = '30') AS A
CROSS APPLY
String.nodes ('/M') AS Split(a);
But I get an error:
"XML parsing: line 2, character 36, illegal name character"
It is not possible to update table and change the data?
Any suggestion?

Assuming (hoping) that the data does not contain the sequence <![CDATA[ and ]]> you could do this:
SELECT CAST('<M><![CDATA[' + REPLACE([csvdata], ',', ']]></M><M><![CDATA[') + ']]></M>' AS XML)
FROM t
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=0409a8643577a8b88e326689ab6da5a7

Related

How to split string in SQL Server

I'm trying to split the value from the model_interested column so that from the whole data only model display
SELECT SUBSTRING(model_interested, 20, CHARINDEX('model', model_interested)) AS model_interested
FROM cust
From the image in model_interested column I wish to only display
"model":"A180"
"model":"A200 AMG FL"
I have tried splitting by number of characters but I don't think it's the right way.
You can use the following solution using SUBSTRING and CHARINDEX:
SELECT SUBSTRING(model_interested, CHARINDEX('"model":"', model_interested) + LEN('"model":"'), CHARINDEX('"', model_interested, CHARINDEX('"model":"', model_interested) + LEN('"model":"')) - (CHARINDEX('"model":"', model_interested) + LEN('"model":"')))
FROM table_name
To get the whole property (with property name and value) you can use the following solution:
SELECT SUBSTRING(model_interested, CHARINDEX('"model":"', model_interested), CHARINDEX('"', model_interested, CHARINDEX('"model":"', model_interested) + LEN('"model":"')) - CHARINDEX('"model":"', model_interested) + 1)
FROM table_name
You can also use JSON_VALUE to get the expected value, but you have to change the data to a valid JSON value:
SELECT JSON_VALUE(REPLACE(REPLACE(model_interested, '{[', '[{'), ']}', '}]'), '$[0].model')
FROM table_name
demo on dbfiddle.uk
If using earlier version of SQL server than 2016, then you can write a query as:
;with cte as
(
SELECT
Split.a.value('.', 'VARCHAR(100)') AS model_interested
FROM (
SELECT CAST ('<M>' + REPLACE([model_interested], '.', '</M><M>') + '</M>' AS XML)
as model_interested_xml
FROM #cust
) AS A CROSS APPLY model_interested_xml.nodes ('/M') AS Split(a)
)
select model_interested
from cte
where CHARINDEX('model',model_interested) > 0
demo here: https://rextester.com/CCW41495

Transpose comma seperated data into rows - some clarification

Let say I have a data
ID String
-------------------
1 John, Adam
Based on the below query transpose comma seperated data into rows
SELECT A.[ID],
Split.a.value('.', 'VARCHAR(100)') AS String
FROM (SELECT [ID],
CAST ('<M>' + REPLACE([string], ',', '</M><M>') + '</M>' AS XML) AS String
FROM TableA) AS A CROSS APPLY String.nodes ('/M') AS Split(a);
Now, I would like to know what is the reason to have '.' and <M> in our query?
PN: Instead of flagging the post please let me know I will delete the post if it should not be post.
If you print out the string within the CAST, you will see that your text string has been turned into an XML string. The '.' in the split command is merely a location in which to start parsing the XML.
If it is sql server 2016 you can use string_split
create table commasep
(
id int identity(1,1)
,string nvarchar(100)
)
insert into commasep (string) values ('John, Adam'), ('test1,test2,test3')
select id, [value] as String from commasep
cross apply string_split(string,',')

Split values into separate rows

WITH Numbers AS (SELECT Table.ProductNumber FROM Table WITH (NOLOCK))
returns ProductNumber like 1, 2, 3,4,5 - some are comma separated, so I want to split and than do proper SELECT on them with WHERE
What I got so far is:
SELECT #XML = CONVERT(xml,'<root><s>' + REPLACE(Numbers , ',' ,'</s><s>') + '</s></root>')
SELECT [ProductNumber ] = T.c.value('.','varchar(60)') FROM #XML.nodes('/root/s') T(c)
But I dont know how to convert selected SQL resource Numbers into string for XML conversion and not loose track of which ProductNumber were in which row
The problem in your query is you are assigning the converted xml to a variable, but here only the last row will be stored in that variable.
Try something like this.
SELECT Split.a.value('.', 'VARCHAR(100)') splt_num
FROM (SELECT Cast ('<M>'
+ Replace(ProductNumber, ',', '</M><M>')
+ '</M>' AS XML) AS Data
FROM yourtable) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)

Group by Clause on a query SQL

I have managed to separate semi colon separated value to multiple rows in sql 2008 what i need now i to have Count(*) statement on it
ID Answers
1 Agent;Department Store
2 Distributor;Wholesaler
using
SELECT ID,
Split.a.value('.', 'VARCHAR(100)') AS String
FROM (SELECT ID,
CAST ('<M>' + REPLACE(Question1, '; ', '</M><M>') + '</M>' AS XML) AS String
FROM Registrations) AS A CROSS APPLY String.nodes ('/M') AS Split(a)
I can get
ID String
1 Agent
1 Department Store
2 Distributor
2 Wholesaler
i just need to get the count(*) of Agent,Department store ..
can i do something like
Select Count(*),String from ( ..above query.. ) group by string ?!
Your attempted query is correct it does work
Do this
select count(*) as Count1,String from
(
SELECT ID,
Split.a.value('.', 'VARCHAR(100)') AS String
FROM (SELECT ID,
CAST ('<M>' + REPLACE(Answers, ';', '</M><M>') + '</M>' AS XML) AS String
FROM #t) AS A CROSS APPLY String.nodes ('/M') AS Split(a)
)x
group by x.String
OR like this?
select count(*) as Count1 from
(
SELECT ID,
Split.a.value('.', 'VARCHAR(100)') AS String
FROM (SELECT ID,
CAST ('<M>' + REPLACE(Answers, ';', '</M><M>') + '</M>' AS XML) AS String
FROM #t) AS A CROSS APPLY String.nodes ('/M') AS Split(a)
)x
SEE DEMO

Getting latest data in a table from comma separated value joining with original table

I have created script to get the comma separated value, that value(cloumn1) joined with another table(column2), (column1) having n number of duplicate I want to get the latest top 1 from column1 and join with column2. script ->
SELECT A.EmailHistoryid,
Split.a.value('.', 'VARCHAR(100)') AS String,
A.MailTo
INTO #tmp
FROM (
SELECT EmailHistoryid,
CAST('<M>' + REPLACE([requestinstanceids], ',', '</M><M>') + '</M>' AS XML) AS String,
MailTo
FROM [emailhistoryDT] NOLOCK
) AS A
CROSS APPLY String.nodes('/M') AS Split(a)
ORDER BY a.EmailHistoryid DESC;