How to convert a horizontal table into vertical table - SQL? - snowflake-cloud-data-platform

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') )

Related

How to Sum (MAX values) from different value groups in same column SQL Server

I have a table like this:
Date
Consec_Days
2015-01-01
1
2015-01-03
1
2015-01-06
1
2015-01-07
2
2015-01-09
1
2015-01-12
1
2015-01-13
2
2015-01-14
3
2015-01-17
1
I need to Sum the max value (days) for each of the consecutive groupings where Consec_Days are > 1. So the correct result would be 5 days.
This is a type of gaps-and-islands problem.
There are many solutions, here is one simple one
Get the start points of each group using LAG
Calculate a grouping ID using a windowed conditional count
Group by that ID and take the highest sum
WITH StartPoints AS (
SELECT *,
IsStart = CASE WHEN LAG(Consec_Days) OVER (ORDER BY Date) = 1 THEN 1 END
FROM YourTable t
),
Groupings AS (
SELECT *,
GroupId = COUNT(IsStart) OVER (ORDER BY Date)
FROM StartPoints
WHERE Consec_Days > 1
)
SELECT TOP (1)
SUM(Consec_Days)
FROM Groupings
GROUP BY
GroupId
ORDER BY
SUM(Consec_Days) DESC;
db<>fiddle
with cte as (
select Consec_Days,
coalesce(lead(Consec_Days) over (order by Date), 1) as next
from YourTable
)
select sum(Consec_Days)
from cte
where Consec_Days <> 1 and next = 1
db<>fiddle

How to select the value from the table based on category_id USING SQL SERVER

How to select the value from the table based on category_id?
I have a table like this. Please help me.
Table A
ID Name category_id
-------------------
1 A 1
2 A 1
3 B 1
4 C 2
5 C 2
6 D 2
7 E 3
8 E 3
9 F 3
How to get the below mentioned output from table A?
ID Name category_id
--------------------
1 A 1
2 A 1
4 C 2
5 C 2
7 E 3
8 E 3
Give a row number for each row based on group by category_id and sort by ascending order of ID. Then select the rows having row number 1 and 2.
Query
;with cte as (
select [rn] = row_number() over(
partition by [category_id]
order by [ID]
), *
from [your_table_name]
)
select [ID], [Name], [category_id]
from cte
where [rn] < 3;
Kindly run this query It really help You Out.
SELECT tbl.id,tbl.name, tbl.category_id FROM TableA as tbl WHERE
tbl.name IN(SELECT tbl2.name FROM TableA tbl2 GROUP BY tbl2.name HAVING Count(tbl2.name)> 1)
Code select all category_id from TableA which has Name entries more then one. If there is single entry of any name group by category_id then such data will be excluded. In above example questioner want to eliminate those records that have single Name entity like wise category_id 1 has name entries A and B among which A has two entries and B has single entry so he want to eliminate B from result set.

How to display results from SQL JOIN as separate columns? [duplicate]

This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 7 years ago.
I am trying to join two tables and then parse out the results into separate columns like so:
Table1:
Customer_ID
----------
1
2
3
Table2:
Customer_ID ListID
------------------
1 1
1 2
1 5
2 1
2 3
Desired Results:
Customer_ID ListID1 ListID2 ListID3
-----------------------------------
1 1 2 5
2 1 3
3
I used a LEFT JOIN to combine the tables and a GROUP BY to group columns with the same Custmer_ID as shown here:
SELECT MIN([Table1].[Customer_ID])
,MIN([Table2].[ListID])
FROM [Table1]
LEFT JOIN [Table2]
ON [Table2].[Customer_ID] = [Table1].[Customer_ID]
GROUP BY [Table1].[Customer_ID]
Current Results:
Customer_ID ListID
------------------
1 1
2 1
3 NULL
I can't figure out where to go from here to parse the ListID's into separate columns. Is there a way to iterate through the ListID's?
This is unique in that the column that you want to pivot for doesn't exist. You can create it with the Row_number window function. It looks like this:
SELECT Customer_ID, [1] ListID1, [2] ListID2, [3] ListID3
FROM
(select Table1.Customer_ID,
Table2.ListID,
ROW_NUMBER() over (Partition by Table1.Customer_ID Order By Table2.ListID) RowNum
from Table1
LEFT JOIN Table2
ON Table2.[Customer_ID] = Table1.[Customer_ID]) as SourceTable
PIVOT
(
max(ListID)
FOR RowNum IN ([1], [2], [3])
) AS PivotTable
This will only show the top three ListID values in the columns. You can add more RowNum values if you need more.

SQL select Top x records for two columns

I have a table like this
ProjectID PhaseID Comment CommentDate
1 1 a 2/15/2014
1 1 b 5/1/2014
1 2 c 8/15/2014
1 2 d 1/1/2015
2 1 e 1/21/2014
2 2 f 5/15/2014
2 2 g 1/1/2015
How do I get the lastest (Top 1) comment for each project for each phase? For example, for Project 1, phase 1, I should get "b" and "5/1/2014"
Thank you!
select ProjectID,PhaseID,Comment,CommentDate from
(select row_number() over(partition by Project_ID,PhaseID order by CommentDate desc) as rn,* from table) a
where a.rn = 1
This type of query works best when there's an identity column (and values are always inserted in order) but this should get you what you need assuming there's no overlapping commentDates
select t.*
from table t
inner join (
SELECT max(commentDate) as maxDate,
phaseId,
projectId
FROM table
group by phaseId, projectId
) maxComments on t.phaseId = maxComments.phaseId
and t.projectId = maxComments.projectId
and t.commentDate = maxComments.maxDate

Get Sum of Count

The View obtains the first three columns. I need to add one more column (totalCount) to the view that obtains the total count:
CId CCId CCount totalCount
1 a 3 6
1 a 3 6
1 b 3 6
1 c 3 6
2 b 2 6
2 b 2 6
2 a 2 6
2 a 2 6
3 v 1 6
How to get the totalCount as 6?
(Business rule for Cid=1 Ccount=3 Cid=2 Ccount=2 Cid=3 Ccount=1 So the totalCount =3+2+1 =6)
SELECT a.CID, a.CCID, a.CCOUNT,
b.TotalCount
FROM Table1 a, (SELECT SUM(DISTINCT cCOunt) TotalCount
FROM Table1) b
SQLFiddle Demo
UPDATE
As Andomar pointed out on the comment, An update has been made on the query,
SELECT a.CID, a.CCID, a.CCOUNT,
b.TotalCount
FROM Table1 a,
(
SELECT SUM(TotalCount) TotalCount
FROM
(
SELECT MAX(cCOunt) TotalCount
FROM Table1
GROUP BY CId
) c
) b
SQLFiddle Demo
With this code I came to the desired result:
select CId
,CCId
,CCount
,(select SUM(a.tcount)
from (select distinct CId ,CCount as tcount
from dbo.Test) as a ) totalcount
from dbo.Test
From your example data, I'm assuming a Cid can only have one, possibly repeated, value of CCount. In that case you can pick a random one (say max) using a group by, and sum those:
select sum(OneCCCount) as TotalCount
from (
select max(CCount) as OneCCCount
from YourTable
group by
CId
) as SubQueryAlias

Resources