Concatenated string split - sql

I have a table Customer in SQL Server 2016 that has a text column with values
I=3;A=500;D=20210422
I would like to split the I=3,A=500 & D=20210422 into 3 columns in a new table or view.

One method is:
select t.*, s.*
from t cross apply
(select max(case when s.value like 'I=%' then stuff(s.value, 1, 2, '') end) as i,
max(case when s.value like 'A=%' then stuff(s.value, 1, 2, '') end) as a,
max(case when s.value like 'D=%' then stuff(s.value, 1, 2, '') end) as d
from string_split(t.col, ';') s
) s;
Here is a db<>fiddle.

Presumably these are just sample values and will vary? If you don't need to guarantee any particular ordering of the columns a simple solution is to use string_split and a conditional case expression to aggregate into new columns:
with v as (
select value, Row_Number() over (order by (select null)) rn
from String_Split('I=3;A=500;D=20210422',';')
)
select
Max(case when rn=1 then value end) Col1,
Max(case when rn=2 then value end) Col2,
Max(case when rn=3 then value end) Col3
from v

This works:
DECLARE #userData TABLE(
var1 varchar(30) NOT NULL,
var2 varchar(30) NOT NULL,
var3 varchar(30) NOT NULL
);
WITH CTE_Data
AS(
SELECT 'I=3,A=500,D=20210422' AS [MyData]
)
,CTE_Detaildata
AS(
SELECT
P.*
FROM(
SELECT
LEFT(v.[Value], 1) [ID],
v.[Value] AS [Data]
FROM CTE_Data AS d
CROSS APPLY STRING_SPLIT(d.[MyData], ',') AS v
)AS D
PIVOT(MIN(D.[Data]) FOR D.[ID] IN ([I],[A],[D])) AS P
)
INSERT INTO #userData(var1, var2, var3)
SELECT
d.[A],
d.[D],
d.[I]
FROM CTE_Detaildata AS d
SELECT * FROM #userData;

Related

SQL Substring to fetch values which inside Bracket only i.e. ()

Might be easy for you expert but I am finding a challenge here-
My column data is as like below, I need to separate out the value which is inside bracket(). My string pattern would always be like this.
J Zeneta (A50103050); S Rao (B499487)
Output should be
Col1 Col2
A50103050 B499487
You can try this, it might need tweaking depending on your RDBMS, this is for SQLServer
select Left(value, CharIndex(')',value)-1) from (
select value from String_Split('J Zeneta (A50103050); S Rao (B499487)','(')
where value like '%)%'
)x
Edit
To have columns a simple case can yeild, like so
select max(case when rn=1 then Value end) Col1, max(case when rn=2 then value end) Col2 from (
select Left(value, CharIndex(')',value)-1) [Value], Row_Number() over (order by (select null)) rn from (
select value from String_Split('J Zeneta (A50103050); S Rao (B499487)','(')
where value like '%)%'
)x
)x
Edit 2
Using data from an existing table example
create table #Test (id int, col varchar(50))
insert into #Test select 1, 'J Zeneta (A50103050); S Rao (B499487)'
insert into #Test select 2, 'Bob Builder (12345); Mr Rambo (67890)'
select id, max(case when (rn % 2)=0 then Value end) Col1, max(case when (rn % 2)!=0 then value end) Col2 from (
select id, Left(value, CharIndex(')',value)-1) [Value], Row_Number() over (order by (select null)) rn from (
select id, value
from #Test t cross apply String_Split(t.col,'(')
where value like '%)%'
)x
)x
group by id

SQL Server Sorting Multiple Values from different columns and reassign them based on ascending value

I have a select statement that brings the values of 5 different columns.
SELECT TOP 1 digit1, digit2, digit3, digit4, digit5 FROM myTable
The result is "25, 36, 1, 63, 12".
My question is, how do I sort these numbers in Ascending order and reassign them to their respectively Ascending columns?
I.E: digit1 = 1, digit2 = 12, digit3 = 25, digit4 = 36, digit5 = 63.
Thanks in advance for the help.
You can do an UNPIVOT followed by a PIVOT
Example
Select *
From (
Select Item = concat('digit',Row_NUmber() over (Order by Value))
,Value
From (Select top 1 * from YourTable) A
UnPivot ( Value for Digits in (digit1,digit2,digit3,digit4,digit5) ) U
) A
Pivot (max(Value) for Item in (digit1,digit2,digit3,digit4,digit5) ) P
Returns
digit1 digit2 digit3 digit4 digit5
1 12 25 36 63
I would use apply:
select v.*
from (select top 1 digit1, digit2, digit3, digit4, digit5 FROM myTable
) t cross apply
(select max(case when seqnum = 1 then digit end) as digit1,
max(case when seqnum = 2 then digit end) as digit2,
max(case when seqnum = 3 then digit end) as digit3,
max(case when seqnum = 4 then digit end) as digit4,
max(case when seqnum = 5 then digit end) as digit5
from (select v.digit, row_number() over (order by v.digit) as seqnum
from (values (digit1), (digit2), (digit3), (digit4), (digit5)
) v(digit)
) v
) v;
If you want to order the results by multiple values, you can use the following syntax.
SELECT TOP 1 digit1, digit2, digit3, digit4, digit5
FROM myTable
ORDER BY digit1, digit2, digit3, digit4, digit5
If the values need manipulation, you may need to create a UDF/CTE or inline expression to determine the 'value' of the columns to order them. Without a full working example (A SQLFiddle would be helpful), it is difficult to be sure.
Using a CTE should allow this to be simplified to something like this. I am assuming that you need this for multiple rows, but simplifying it to a single row is easier than expanding a solution to multiple rows
WITH MyData as (
SELECT ID, digit1 as Digit FROM myTable
UNION ALL
SELECT ID, digit2 FROM myTable
UNION ALL
SELECT ID, digit3 FROM myTable
UNION ALL
SELECT ID, digit4 FROM myTable
UNION ALL
SELECT ID, digit5 FROM myTable
)
SELECT ID, Digit
FROM MyData
ORDER BY ID, Digit
Your data is now in order. A simple PIVOT will give you the output you are looking for.

Sql Server 2008 table join

I have written one query in SQL. I can't get correct output.
here I have attached screenshot.
This is query Output
but I want it like this
You don't need the union subquery (unless you need to remove duplicates). This should do what you want:
select max(case when status = 'O' then ref end) as O,
max(case when status = 'E' then ref end) as E,
max(case when status = 'A' then ref end) as A
from (select p.*, row_number() over (partition by status order by status) as seqnum
from nl_pmnt
where status in ('O', 'E', 'A')
) p
group by seqnum
Try this:
select [O],[E],[A] from (
select row_number() over (order by (select null)) [RN], ref [O] from nl_pmnt where [status] = 'O' and ref <> ''
) [O] left join (
select row_number() over (order by (select null)) [RN], ref [E] from nl_pmnt where [status] = 'O' and ref <> ''
) [E] on [O].[RN] = [E].[RN] left join (
select row_number() over (order by (select null)) [RN], ref [A] from nl_pmnt where [status] = 'O' and ref <> ''
) [A] on [O].[RN] = [A].[RN]
You can use PIVOT
SELECT [O],[E],[A] FROM (
select ROW_NUMBER() OVER( PARTITION BY status ORDER BY (SELECT NULL)) RN, ref, status from nl_pmnt
where ref <> '') SRC
PIVOT(MAX(ref) FOR status IN ([O],[E],[A])) PVT

convert row into column with asc order in oracle

SELECT * FROM
(
SELECT TEST_NAME, SBNO, VAL
FROM TABLE1
)
PIVOT (
MAX(VAL)
FOR SBNO in (1 value1, 2 value2, 3 value3 ));
Output:
I want to show data in ascending order, like this:
2.3 , 2.4 , 2.5
but result is
2.3 , 2.5 , 2.4
This would do the trick. I have created a new SBNO column, ordering by test_name and value and then PIVOT operator will do the rest.
;with cte as (
select
test_name
,val
,'Value' + cast(ROW_NUMBER() over (partition by test_name order by test_name, val) as varchar(5)) as new_SBNO
from TABLE1
)
select *
from cte
pivot (
max(val)
for new_SBNO in (value1, value2, value3)
) pvt
I would do this using conditional aggregation:
select test_name,
max(case when seqnum = 1 then val end) as value_1,
max(case when seqnum = 2 then val end) as value_2,
max(case when seqnum = 3 then val end) as value_3
from (select t1.*,
row_number() over (partition by test_name order by val asc) as seqnum
from table1 t1
) t1
group by test_name;
You could express this with pivot. And in Oracle, pivot can even be a bit faster. I just find conditional aggregation to be more flexible and simpler to implement.

row convert to column in sql 2008

I want to convert a series of rows into a series of columns
create table #cusphone(cusid int,cusph1 int)
insert into #cusphone values(1,48509)
insert into #cusphone values(1,48508)
insert into #cusphone values(1,48507)
insert into #cusphone values(2,48100)
so that the output is like this
1 48509 48508 48507
2 48100 null null
You can use the same approach of rank() and then use the new PIVOT function as follows:
with cusCte as(
select cusid,cusph1,RANK() over (partition by cusid order by cusph1) r
from #cusphone)
SELECT cusid, [1] AS C1, [2] AS C2, [3] AS C3
FROM
(SELECT cusid,cusph1,r
FROM cusCte) p
PIVOT
(
MIN (cusph1)
FOR r IN
( [1], [2], [3] )
) AS pvt;
You did not specify the rules by which something should appear in the first column vs the second column so I guessed that this is based on the occurrence (and thus sorting) of the cusph1 value.
With RankedItems As
(
Select cusid, cusph1
, ROW_NUMBER() OVER( PARTITION BY cusid ORDER BY cusph1 DESC) As Num
From #cusphone
)
Select cusid
, Min(Case When Num = 1 Then cusph1 End) As Col1
, Min(Case When Num = 2 Then cusph1 End) As Col2
, Min(Case When Num = 3 Then cusph1 End) As Col3
From RankedItems
Group By cusid