Transposing only few columns in SQL Server - sql-server

I have 4 columns in my table like :
key cusi isi name
1 46644UAQ1 US46642EAV83 A
1 46644UAR9 XS0062104145 A
1 254206AC9 A
2 05617YAJ8 US86359AXP38 B
2 885220BP7 B
2 null B
3 885220BP5 885220BP7345 c
the key and name column content is getting duplicated because of the cusi and isi column .I would like to transpose only few columns in this case cusi and isi column so that i get 1 record of id =1 and another one for id=2 .In my use case there can be at the max 3 ditinct cusi or 3 isi column.
The transpose table should like
key name cusi1 cusi2 cusi3 isi1 isi2 isi3
1 A 46644UAQ1 46644UAR9 254206AC9 US46642EAV83 XS0062104145 NULL
2 A 46644UAR9 05617YAJ8 885220BP7 US86359AXP38 NULL NULL
3 c 885220BP5 null null 885220BP7345 NULL NULL
In some cases there might be only 1 row like in t he above example it is for key= 3
i know that sql has PIVOT and UNPIVOT queries but i am not sure how to use it for transposing selecting columns of a table
Any help would be of great help.
Thanks

If you know that each key-name group will have a fixed number of records (three, based on the sample data you gave us), then an ordinary non pivot should work. In the query below, I make use of the row number to distinguish each of the three columns you want for cusi and isi in your result set.
SELECT t.key,
t.name,
MAX(CASE WHEN t.rn = 1 THEN cusi END) AS cusi1,
MAX(CASE WHEN t.rn = 2 THEN cusi END) AS cusi2,
MAX(CASE WHEN t.rn = 3 THEN cusi END) AS cusi3,
MAX(CASE WHEN t.rn = 1 THEN isi END) AS isi1,
MAX(CASE WHEN t.rn = 2 THEN isi END) AS isi2,
MAX(CASE WHEN t.rn = 3 THEN isi END) AS isi3
FROM
(
SELECT key,
cusi,
isi,
name,
ROW_NUMBER() OVER(PARTITION BY key ORDER BY cusi) AS rn
FROM yourTable
) t
GROUP BY t.key,
t.name
Note that SQL Server also has a PIVOT function, which is an alternative to what I gave.

Related

How to convert a horizontal table into vertical table - SQL?

I have a table on Snowflake
category
Metric1
Metric2
Metric3
First
1
2
3
Second
4
5
6
And I want my table to be like:
Metrics
First
Second
Metric1
1
4
Metric2
2
5
Metric3
3
6
I have a way of doing this with UNPIVOT function in Snowflake-SQL:
SELECT * FROM my_table
UNPIVOT
(DATA for Metrics in
(
Metric1,
Metric2,
Metric3
)
)
However, it somehow returns to
CATEGORY
METRICS
DATA
FIRST
Metric1
1
FIRST
Metric2
2
FIRST
Metric3
3
SECOND
Metric1
4
SECOND
Metric2
5
SECOND
Metric3
6
which is not something I want.
Could anyone please help me with this in one SQL query without creating a new table?
I think there is a way to solve this issue with UNPIVOT, but I couldn't figure this out. Thank you!
One method is a lateral join and aggregation:
select v.metric,
max(case when t.category = 'First' then v.value end) as first,
max(case when t.category = 'Second' then v.value end) as second
from t cross join lateral
(values ('Metric1', metric1),
('Metric2', metric2),
('Metric3', metric3)
) v(metric, value)
group by v.metric;
You were spot on in your original SQL ... just needed to PIVOT the Category back:
SELECT * FROM
(
SELECT * FROM CTE UNPIVOT
( DATA FOR METRICS IN (METRIC_1, METRIC_2, METRIC_3))
)
PIVOT (SUM (DATA) FOR CATEGORY IN ('FIRST','SECOND') )
Copy|Paste|Run
WITH CTE AS
(SELECT 'FIRST' CATEGORY, 1 METRIC_1 ,2 METRIC_2,3 METRIC_3
UNION
SELECT 'SECOND' CATEGORY, 4 METRIC_1 ,5 METRIC_2,6 METRIC_3)
SELECT * FROM
(
SELECT * FROM CTE UNPIVOT ( DATA FOR METRICS IN (METRIC_1, METRIC_2, METRIC_3))
)
PIVOT (SUM (DATA) FOR CATEGORY IN ('FIRST','SECOND') )

How to query records based on row_num and one of the column value?

Rownum Status
1 2
2 1
3 3
4 2
5 3
6 1
The condition is to query records appear before the first record of status=3 which in the above scenario the expected output will be rownum = 1 and 2.
In the case if there is no status=3 then show everything.
I'm not sure from where to start hence currently no findings
If you are using SQL Server 2012+, then you can use window version of SUM with an ORDER BY clause:
SELECT Rownum, Status
FROM (
SELECT Rownum, Status,
SUM(CASE WHEN Status = 3 THEN 1 ELSE 0 END)
OVER
(ORDER BY Rownum) AS s
FROM mytable) t
WHERE t.s = 0
Calculated field s is a running total of Status = 3 occurrences. The query returns all records before the first occurrence of a 3 value.
Demo here

Pivot with ID and Dates

I have this data set and Im trying to create a pivot table for the data below. I having some issues when trying to put in the date for each type across.
Member ID Type Date
1 A 12/5/2014
1 b 3/6/2014
2 a 6/9/2015
2 b 3/2/2015
2 c 6/1/2014
3 a 6/5/2014
3 c 7/6/2014
4 c 9/13/2014
5 a 7/25/2014
5 b 6/24/2014
5 c 2/24/2014
Then
I would like it to come out as a pivot table, like this:
Member ID A A date B B date c C date
1 Yes 12/5/2014 yes 3/6/2014 Null Null
2 Yes 6/9/2015 yes 3/2/2015 Yes 6/1/2014
3 Yes 6/5/2014 Null Null Yes 7/6/2014
4 Null Null Null Null Yes 9/13/2014
5 Yes 7/25/2014 yes 6/24/2014 Yes 2/24/2014
i got this far not including the dates
SELECT
MemberID
,Type
--,Date
into #Test9
FROM [Data].[dbo].[Test]
I create the Temp table then try to pivot without date
Select *
From #Test9
Pivot ( count(type)
for type in (a]
,[b]
,[c])) as pvt
Would someone please help.
Assuming each member will only have one value for each type you could use conditional aggregation to get the result you want:
select
memberid,
max(case when type='a' then 'Yes' end) as "a",
max(case when type='a' then date end) as "a date",
max(case when type='b' then 'Yes' end) as "b",
max(case when type='b' then date end) as "b date",
max(case when type='c' then 'Yes' end) as "c",
max(case when type='c' then date end) as "c date"
from your_table
group by MemberID
Sample SQL Fiddle
This can quite easily be turned into a dynamic query if you don't have a fixed number of types; there are plenty of good answers here on Stack Overflow that demonstrates how, including the canonical SQL Server Pivot question that I usually link to.
try
declare #t table(memberid int,[type] char(1),[date] date)
insert into #t(MemberID,[Type],[Date]) values
( 1,'A','12/5/2014'),
(1,'b','3/6/2014'),
(2,'a','6/9/2015'),
(2,'b','3/2/2015'),
(2,'c','6/1/2014'),
(3,'a','6/5/2014'),
(3,'c','7/6/2014'),
(4,'c','9/13/2014'),
(5,'a','7/25/2014'),
(5,'b','6/24/2014'),
(5,'c','2/24/2014')
select memberid, case when len(a)>0 then 'Yes' end as [A date],a,
case when len(b)>0 then 'Yes' end as [B date],b,
case when len(c)>0 then 'Yes' end [c date] ,c from #t t
pivot( max([date]) for [type] in (a,b,c)) p

sql query to display the input data

I want a SQL query to display the following data
Input Data:
ID GroupID Data
1 1 Hello
2 1 Null
3 1 Null
4 1 World
5 2 Niladri
6 2 XXX
7 2 Null
8 2 PPP
9 2 Null
10 2 Null
11 2 Null
12 2 LLL
as
Output Data:
GroupID MergedData
1 Hello2World
2 NiladriXXX1PPP3LLL
I need to group the data on GroupID and display the result as Hello2World
-->Hello is related to GroupID 1
-->2 is count of NULLS
-->World is related to GroupID 1
Similarly for GroupID 2.
Kindly suggest?
Thanks
As you did not mention your DBMS, this is a solution for PostgreSQL:
SELECT groupid,
string_agg(temp_data,'')
FROM (
SELECT id,
groupid,
data,
CASE
WHEN data IS NULL
THEN cast(max(rn) over (partition by groupid, data) as varchar)
ELSE data
END AS temp_data,
row_number() over (partition by groupid, data) as group_rn
FROM (
SELECT id,
groupid,
data,
CASE
WHEN data IS NULL
THEN row_number() over (partition by groupid,data)
ELSE NULL
END AS rn
FROM foo
) t1
ORDER BY id
) t2
WHERE group_rn in (0,1)
GROUP BY groupid
If your DBMS supports ANSI windowing functions and has something similar like the string_agg() function then this should be portable to your DBMS as well.

ssis merge join more than 2 data sets

I'm working on an ssis package to fix some data from a table. The table looks something like this:
CustID FieldID INT_VAL DEC_VAL VARCHAR_VAL DATE_VAL
1 1 23
1 2 500.0
1 3 David
1 4 4/1/05
1 5 52369871
2 1 25
2 2 896.23
2 3 Allan
2 4 9/20/03
2 5 52369872
I want to transform it into this:
CustID FirstName AccountNumber Age JoinDate Balance
1 David 52369871 23 4/1/05 500.0
2 Allan 52369872 25 9/20/03 896.23
Currently, I've got my SSIS package set up to pull in the data from the source table, does a conditional split on the field id, then generates a derived column on each split. The part I'm stuck on is joining the data back together. I want to join the data back together on the CustId.
However, the join merge only allows you to join 2 datasets, in the end I will need to join about 30 data sets. Is there a good way to do that without having to have a bunch of merge joins?
That seems a bit awkward, why not just do it in a query?
select
CustID,
max(case when FieldID = 3 then VARCHAR_VAL else null end) as 'FirstName',
max(case when FieldID = 5 then INT_VAL else null end) as 'AccountNumber',
max(case when FieldID = 1 then INT_VAL else null end) as 'Age',
max(case when FieldID = 4 then DATE_VAL else null end) as 'JoinDate',
max(case when FieldID = 2 then DEC_VAL else null end) as 'Balance'
from
dbo.StagingTable
group by
CustID
If your source system is MSSQL, then you can use that query from SSIS or even create a view in the source database (if you're allowed to). If not, then copy the data directly to a staging table in MSSQL and query it from there.

Resources