I use Azure SQL database. I have a table - test_excel_poc_head with the below values which I want to transpose using link id values as the columns
The intended output is below where the column is the 'link_id' values. The link_id values are dynamic
I started using UNPIVOT and PIVOT option and below is my unpivot query and results:
SELECT link_id,head_values
FROM
(SELECT link_id,comp1,comp2,comp3,comp4
FROM [dbo].[test_excel_poc_head]
) AS cp
UNPIVOT
(head_values FOR head_value in (comp1,comp2,comp3,comp4)
) AS up
RESULTS:
Now when I add the PIVOT code, it expects an aggregate function which I do not have as it is a string and it errors out.
If I add MAX as the aggregate function, I do not get the intended result.
SELECT * FROM (
SELECT link_id,head_values
FROM
(SELECT link_id,comp1,comp2,comp3,comp4
FROM [dbo].[test_excel_poc_head]
) AS cp
UNPIVOT
(head_values FOR head_value in (comp1,comp2,comp3,comp4)
) AS up
) temp_results
PIVOT(
MAX(head_values)
FOR link_id
IN (
[1],[2],[3],[4],[5],[6]
)
) AS PivotTable
RESULT:
But this is not my expected result. Is there any other option to achieve PIVOT without the use of agg functions?
Thanks for your time and help.
I tried my luck. Could you check below query if it works,
What I did different to your query is making the result of UNPIVOT distinct by adding row_number to it so that the later PIVOT will take max of each row and display separately. My bad if the explanation doesn't makes sense to you.
select [1],[2],[3],[4],[5],[6]
from
( select link_id,head_values,
row_number() over (partition by link_id order by link_id) rn
from
( select link_id
,cast(comp1 as varchar(255)) as comp1
,cast(comp2 as varchar(255)) as comp2
,cast(comp3 as varchar(255)) as comp3
,cast(comp4 as varchar(255)) as comp4
from [dbo].[test_excel_poc_head]
) as cp
unpivot
(
head_values for head_value in (comp1,comp2,comp3,comp4)
) as up
) temp_results
pivot
(
max(head_values)
for link_id in ([1],[2],[3],[4],[5],[6])
) as pivottable;
db<>fiddle for your reference.
Related
I have an SQL query working with Pivot,
I have some plans records (table Plan) and on each plan I have an amount each month (table PlanMonth).
this is an example how it works with pivot.
select PlanId,[1] Jan,[2]Feb,[3]Mar,[4]Apr,[5]May,[6]Jun,[7] July,[8]Aug,[9]Sep,[10]Oct,[11]Nov,[12] Dec
from(
select Plan.Id PlanId,PlanMonth.Amount,PlanMonth.Month
from PlanTable
left join PlanMonth on
LockAmount.IdPlan = rpo.Id
)p
PIVOT
(
SUM (Amount)
FOR Month IN
( [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) AS pvt
and I want to add another more columns from another table (LockAmount table) linked by IdPlan
and this is the example:
select PlanId,[1] LockAmount1,[2] LockAmount2,[3] LockAmount3,[4] LockAmount4
from(
select Plan.Id PlanId,LockAmountTable.LockAmount,LockAmountTable.NumForecast
from PlanTable
left join LockAmountTable on
LockAmount.IdPlan = rpo.Id
)p
PIVOT
(
SUM (LockAmount)
FOR NumForecast IN
( [1][1],[2],[3],[4])
) AS pvt
this is how the table structure is done
My question how to apply multiple pivot to show the data in this form
From what I understand from the question is can we have multiple pivots and want to integrate using both the queries shared. Yes, we can go with the approach of CTE until same column is present in both the sub-queries. Below is the query that might be helpful.
; with pivot_1 as
(
select pvt1.PlanId as pvt1PlanID,pvt1.[1] Jan,pvt1.[2]Feb,pvt1.[3]Mar,pvt1.[4]Apr,pvt1.[5]May,pvt1.[6]Jun,pvt1.[7] July,pvt1.[8]Aug,pvt1.[9]Sep,pvt1.[10]Oct,pvt1.[11]Nov,pvt1.[12] Dec
from(
select Plan.Id PlanId,PlanMonth.Amount,PlanMonth.Month
from PlanTable
left join PlanMonth on
LockAmount.IdPlan = rpo.Id
)p
PIVOT
(
SUM (Amount)
FOR Month IN
( [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
) AS pvt1
), pivot_2 as (
select pvt2.PlanId as pvt2PlanID,pvt2.[1] LockAmount1,pvt2.[2] LockAmount2,pvt2.[3] LockAmount3,pvt2.[4] LockAmount4
from(
select Plan.Id PlanId,LockAmountTable.LockAmount,LockAmountTable.NumForecast
from PlanTable
left join LockAmountTable on
LockAmount.IdPlan = rpo.Id
)p
PIVOT
(
SUM (LockAmount)
FOR NumForecast IN
( [1][1],[2],[3],[4])
) AS pvt2)
select * from pivot_1 p1
inner join pivot_2 p2 on p1.pvt1PlanID=p2.pvt2PlanID
I have found many answers to this question, but all of them leave me stymied as to actually making it work. Apparently, I am just being dense today. Can someone just give me the code to make this work?
My T-SQL query returns the following rows:
Before
I need to transpose the rows and columns:
Like this
unpivot —> pivot
select p.*
from
(
--My T-SQL query returns the following rows:
select *
from
(
values
('A',1,2,3,4,5,6,7,8),('B',10,20,30,40,50,60,70,80),
('C',100,200,300,400,500,600,700,800), ('I',11,22,33,0,0,0,0,88)
) as t(product_code,week_1,week_2,week_3,week_4,week_5,week_6,week_7,week_8)
) as s
unpivot
(
thevalue for weekno in (week_1,week_2,week_3,week_4,week_5,week_6,week_7,week_8)
) as u
pivot
(
max(thevalue) for product_code in (A,B,C,D,E,F,G,H,I,J)
) as p;
I need to calculate the Prevdate as shown below without using CTE or temp tables. I tried using lead it applied for only one row above. Also the number of record for each group might vary. Can anyone suggest a solution here?
Below is the sample data:
create table #Sampledata
(
id int
,groupno int
,Date date
)
insert into #Sampledata values (
1,1,'1/2/2020'),
(2,2,'1/13/2020'),
(3,2,'1/13/2020'),
(4,2,'1/13/2020'),
(5,3,'1/24/2020')
Below is the expected output:
What you are calling the previous date is really the next date. That just helps understanding the question.
Unfortunately, SQL Server does not fully support range window frames, so window functions (at least in a simple manner) are not appropriate.
One method is using lead() in an aggregation subquery and joining the results in:
select sd.*, g.next_date
from sampledata sd join
(select groupno, lead(min(date)) over (order by groupno) as next_date
from Sampledata
group by groupno
) g
on sd.groupno = g.groupno;
Another option is cross apply:
select sd.*, x.next_date
from sampledata sd outer apply
(select top (1) min(sd2.date) as next_date
from sampledata sd2
where sd2.date > sd.date
) x;
Of course, if the groups really are sequentially enumerated, you can replace sd2.date > sd.date with sd2.groupno = sd.groupno + 1.
Here is a db<>fiddle.
try joining with one reduced this works only if groupno is continued.
select distinct s1.* , s2.PrevDate
from #Sampledata as s1
left join (
select groupno - 1 as num , [Date] as PrevDate
from #Sampledata
) as s2 on s1.groupno = s2.num
Edit: I caused a cartesian explosion so I just rammed a distinct in there to sort it out
I have data in a view where the Col_Head column values are supposed to be column headers(they are constant for every sequence of data from 1-8.
And Value column entries need to come as row values.
I need to write some SQL that transposes/pivots rows from Col_Head as column headers.
Example:
Expected data:
If you had a specific Id for each person then you didn't need to create CTE, any way
First, I create specific Id for each person like this via CTE:
/*Create CTE*/
With tempTable as
(
select
row_number() over( order by(select 0) ) row_num,
*
from myTable
),newTable as(
select
case when (row_num %8)>0 then (row_num /8)+1 else (row_num /8) end sp_Id,
*
from tempTable
)
/*MainQuery*/
select
*
from (select sp_id, Col_Header,[Value] from newTable )as temp
pivot
(
max([Value])
for Col_Header in ([Emp name],[Emp Dept],[Emp Grade],[Emp class],[Emp Sal],[Emp manager],[Emp Date of join],[Emp documents])
) pivotTable
This is my table structure !
create table t(floor int,apt int)
insert into t values(1,1),(1,2),(1,4),(2,5),(2,6),(2,7)
I want to get like this!
floor room1 room2 room3
1 1 2 4
2 5 6 7
Use a PIVOT in this case.
SELECT * FROM
(
SELECT floor,
apt,
NumberedApt = 'room' + CAST(ROW_NUMBER() OVER
(PARTITION BY floor ORDER BY apt) AS NVARCHAR(100))
FROM t
) AS OrderApts
PIVOT (MAX(apt) FOR Numberedapt IN (room1, room2, room3)) AS PivotedApts
Here is and SQLFiddle of the above working.
If you are going to get many more 'room' columns then you might want to consider using a dynamic pivot, but they can be inefficient due to not having a query plan.
More on pivot here
1.you need to use Row_number() partition by floor to get row then pivot to get your requirement
select p.floor,p.[1] as room1,p.[2] as room2,p.[3] as room3 from
(
select floor,apt,row_number() over(partition by floor order by apt) as rn from #t) as t
pivot
(
min(t.apt)
for t.rn in([1],[2],[3])
)as p;
See in Action