need to split a column value - sql

I have a below table
id name total
1 a 2
2 b 3
3 c,d,e,f 15
Expected Output:-
id name total
1 a 2
2 b 3
3 c 15
4 d 15
5 e 15
5 f 15
I tried split function and also XML, but didn't work.

As you dont specify the DB name, Assuming SQL SERVER. You can try this one.
Working Example
SELECT A.[id],
Split.a.value('.', 'VARCHAR(100)') AS String,A.total
FROM (SELECT [id],
CAST ('<M>' + REPLACE([name], ',', '</M><M>') + '</M>' AS XML) AS String ,
[total]
FROM #t) AS A
CROSS APPLY String.nodes ('/M') AS Split(a);
Refer this article

Which version of SQL are you using?
The split function is for splitting a string of text, but what you are requesting is a change to the format of the table itself.
Your table has a tuple of id=3, name=c,d,e,f, total=15.
If you want id=3, name=c and so on, you have to change the data.
From the way your question is phrased, it implies that you want the data to be presented in a different way, but the id is the defining column which differentiates between rows in the database.
You could automatically generate a new table, in which case the split statement would be useful to get each element out of your comma separated record.
Once you have that list of items, assuming your id field is an identity field (auto incrementing), you could run an insert statement for each element.
You might be able to get the sort of output you're looking for using an inner select that splits the comma separated list of values, but you would need some procedural SQL (or T-SQL... you do not specify your SQL server) to iterate over the values and insert them into a new table.
If you do go down this route, the id values will have to be thrown away, and you would treat the list as just a raw data set.
EDIT: The example posted by Have No Display Name is about as close as you're going to get with the data in the form it is.
The IDs for the names 'c','d','e' and 'f' will all be 3, but your format will be very close.

Related

How do I get a comma-delimited list of strings from an XML column in T-SQL?

Suppose there is a table (SQL Server 2019) with two columns. Both are nvarchar but the ResultDoc column happens to store xml. Example data:
Name
ResultDoc
Sam
<doc><results><result>a</result><result>b</result><result>x</result></results></doc>
Jan
<doc><results><result>c</result><result type="pending">z</result><result>m</result><result>k</result></results></doc>
I want to be able to query this table, filtering on the xml, and get a result like this:
Name
Results
Sam
a, b, x
Jan
c, m, k
I've seen examples that do this for a single document, but I haven't been able to work a solution like that into a query that does this for several rows.
Updated ... moved the aggregate into the OUTER APPLY
Since you are on 2019, you can use string_agg()
Example or dbFiddle
Select A.Name
,C.Results
From YourTable A
Outer Apply ( values (try_convert(xml,[ResultDoc]) ) )B(xmlData)
Outer Apply (
Select Results = string_Agg(xn.value('./text()[1]', 'nvarchar(150)'),',')
From xmlData.nodes('doc/results/result') C(xn)
Where coalesce(xn.value('#type[1]', 'nvarchar(150)'),'') not in ('pending')
) C
Results
Name Results
Jan c,m,k
Sam a,b,x

SAP HANA SQL - Concatenate multiple result rows for a single column into a single row

I am pulling data and when I pull in the text field my results for the "distinct ID" are sometimes being duplicated when there are multiple results for that ID. Is there a way to concatenate the results into a single column/row rather than having them duplicated?
It looks like there are ways in other SQL platforms but I have not been able to find something that works in HANA.
Example
Select
Distinct ID
From Table1
If I pull only Distinct ID I get the following:
ID
1
2
3
4
However when I pull the following:
Example
Select
Distinct ID,Text
From Table1
I get something like
ID
Text
1
Dog
2
Cat
2
Dog
3
Fish
4
Bird
4
Horse
I am trying to Concat the Text field when there is more than 1 row for each ID.
What I need the results to be (Having a "break" between results so that they are on separate lines would be even better but at least a "," would work):
ID
Text
1
Dog
2
Cat,Dog
3
Fish
4
Bird,Horse
I see Kiran has just referred to another valid answer in the comment, but in your example this would work.
SELECT ID, STRING_AGG(Text, ',')
FROM TABLE1
GROUP BY ID;
You can replace the ',' with other characters, maybe a '\n' for a line break
I would caution against the approach to concatenate rows in this way, unless you know your data well. There is no effective limit to the rows and length of the string that you will generate, but HANA will have a limit on string length, so consider that.

How to normalize a multi-values in a single field (SQL)

I have a table which consists of column names Foo & Bar where Foo is a unique ID and bar contains multi-values seperated by ~
Foo Bar
1 A~B~
2 A~C~D
I need it to be normalised as such:
Foo Bar
1 A
1 B
2 A
2 C
2 D
While I can do it from Excel by separating TEXT to Column followed by pivoting, it is not doable as I have 1 million over records and Bar column may contain up to 12 different values.
Is there a simple way which I could manipulate straight from SQL?
you have a standard 1 to many relationship here. so you have 1 Foo to many Bars. So you need to make your data abide by 2nd Normal Form here (2NF).
Here is a SO post explaining the best way to split the string column value into rows like you want:
Turning a Comma Separated string into individual rows
You didn't specify your DBMS so this is for Postgres:
select t.foo, b.bar
from the_table t,
unnest(string_to_array(t.bar, '~')) as b(bar);
Thanks all. The script below works wonder even though I do not understand XML or the logic.
SELECT A.FOO,
Split.a.value('.', 'VARCHAR(100)') AS Data
FROM
(
SELECT FOO,
CAST ('' + REPLACE(BAR, ',', '') + '' AS XML) AS Data
FROM Table1
) AS A CROSS APPLY Data.nodes ('/M') AS Split(a);
Reference:
Turning a Comma Separated string into individual rows

How can I "dynamically" split a varchar column by specific characters?

I have a column that stores 2 values. Example below:
| Column 1 |
|some title1 =ExtractThis ; Source Title12 = ExtractThis2|
I want to remove 'ExtractThis' into one column and 'ExtractThis2' into another column. I've tried using a substring but it doesn't work as the data in column 1 is variable and therefore it doesn't always carve out my intended values. SQL below:
SELECT substring(d.Column1,13,24) FROM dbo.Table d
This returns 'Extract This' but for other columns it either takes too much or too little. Is there a function or combination of functions that will allow me to split consistently on the character? This is consistent in my column unlike my length count.
select substring(col1,CHARINDEX('=',col1)+1,CHARINDEX (';',col1)-CHARINDEX ('=',col1)-1) Val1,
substring(col1,CHARINDEX('=',col1,CHARINDEX (';',col1))+1,LEN(col1)) Val2
from #data
there is duplicate calculation that can be reduced from 5 to 3 to each line.
but I want to believe this simple optimization done by SQL SERVER.

SQL Select using distinct and Cast [duplicate]

This question already exists:
Closed 10 years ago.
Possible Duplicate:
SQL Select DISTINCT using CAST
Let me try this one more time... I'm not a sql guy so please bear with me as I try to explain this... I have a table called t_recordkeepingleg with three columns of data. Column1 is named LEGTRIPNUMBER that happens to be a string that starts with the letter Q followed by 4 numbers. I need to strip off the Q and convert the remaining 4 characters (numbers) to an integer. Everyone with me so far? Column2 of this table is named LEGDATE. Column3 is named LEGGROUP.
Here's the input scenario
LEGTRIPNUMBER LEGDATE LEGGROUP
Q1001 08/12/12 0001
Q1001 09/15/12 0002
Q1002 09/01/12 0001
Q1002 09/08/12 0003
Q1002 09/09/12 0002
As you can see the input table has rows where LEGTRIPNUMBER occurs more than once. I only want the first occurrence.
This is my current select statement - it works but returns all rows.
SELECT *,
CAST(
substring("t_RecordkeepingLeg"."LEGTRIPNUMBER",2,4) as INT
) as Num_Trip_Num
FROM "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where left "t_RecordkeepingLeg"."LEGTRIPNUMBER",1) = 'Q'
I want to modify this so that it only selects ONE occurance of the Qnnnn. When the row gets selected I want to have LEGDATE and LEGGROUP available to me. How do I do this?
Thank you,
Can it be as simple as below? I've just added condiotion on leggroup being 0001
SELECT *,
CAST(substring("t_RecordkeepingLeg"."LEGTRIPNUMBER",2,4) as INT) as Num_Trip_Num
FROM "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where left ("t_RecordkeepingLeg"."LEGTRIPNUMBER",1) = 'Q'
and "t_RecordkeepingLeg"."LEGGROUP"='0001'
If you have a unique primay key in your table you can do something like the below;
SELECT CAST(
substring("t_RecordkeepingLeg"."LEGTRIPNUMBER",2,4) as INT
) as Num_Trip_Num
FROM "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where "t_RecordkeepingLeg"."ID" In(
Select Min("t_RecordkeepingLeg"."ID")
From "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where left ("t_RecordkeepingLeg"."LEGTRIPNUMBER",1) = 'Q'
Group By "t_RecordkeepingLeg"."LEGTRIPNUMBER"
)
Which values of LEGDATE & LEGGROUP do you want for the distinct LEGTRIPNUMBER? there are multiple non-distinct possibilities and the concept of "first occurrence" is only valid with an explicit order.
To get the values where LEGDATE is the earliest for example;
select Num_Trip_Num, LEGDATE, LEGGROUP from (
select
cast(substring(t_RecordkeepingLeg.LEGTRIPNUMBER, 2, 4) as INT) as Num_Trip_Num,
row_number() over (partition by substring(t_RecordkeepingLeg.LEGTRIPNUMBER, 2, 4) order by t_RecordkeepingLeg.LEGDATE asc) as row,
t_RecordkeepingLeg.LEGDATE,
t_RecordkeepingLeg.LEGGROUP
from t_RecordkeepingLeg
where left (t_RecordkeepingLeg.LEGTRIPNUMBER, 1) = 'Q'
) T
where row = 1