I have written the query to get the first result in SQL Server.
And I want to pivot this table into the following format. I need help pivoting this table in SQL Server.
You can go for simple PIVOT as given below:
DECLARE #table table(division varchar(30), emp int, month varchar(30))
INSERT INTO #table
values
('AAA',50,'December')
,('BBB',100,'December')
,('AAA',200,'January')
,('BBB',150,'January')
,('AAA',60,'February')
,('BBB',70,'February ')
SELECT * FROM #table
pivot (sum(emp) for month in ([December],[January],[February])) as pvt
division
December
January
February
AAA
50
200
60
BBB
100
150
70
If you want to Pivot a table in sql server here is how you do it
select [Division],[December],[January],[February]
from(
select * from SOF
) tbl
pivot(
Min(Emp) for Month in ([December],[January],[February])
) pvt
This query will get your results according to provided data. This is how PIVOT works.
select
<non pivot column 1>,
<non pivot column 2>,
<pivoted column 1>,
<pivoted column 2>,
............
from (
--Result from the query
select * from yourTable
) tbl
pivot(
<Aggregation function> For [<column that contains the values that will become column headers>]
IN ( [first pivoted column], [second pivoted column],
... [last pivoted column])
)
Related
I am trying to convert my rows into columns, or my columns into rows... I am a little confused with which it is exactly but here's what I would want it to look like
Original table:
Month | Price
1 500
2 600
3 700
what it needs to look like:
1 2 3
500 600 700
Could anyone tell me how his could be done?
EDIT:
CREATE table #yourtable (
[Id] int,
[Value] varchar(6),
[ColumnName] varchar(13)) ;
INSERT INTO #yourtable (
[Id],
[Value],
[ColumnName])
VALUES
(1, '1', 'Month'),
(2, '500', 'Price') ;
select
Month,
Price
from (
select
value,
columnname
from #yourtable ) d
pivot
(max(value) for columnname in (Month, Price) ) piv;
You wrote an almost correct query.
select
Month,
Price
from (
select
value,
columnname
from #yourtable) d
pivot
(max(value) for columnname in ('Month' AS Month, 'Price' AS Price) ) piv;
I have a table like this:
TableName
dates
ModelName
BaseUnitPerPallet
pallet
Calendar
June
Null
4
1
Country
June
Null
2
6
Product
June
DOWNSTREAM
Null
8
ProductBOM
June
DOWNSTREAM
9
9
and I want a table like this:
Columns
values
TableName
Calendar
TableName
Country
TableName
Product
TableName
ProductBOM
where columns field is the headers of the previous table, and values are the values in an unpivot way.
I have been trying without success the unpivot logic:
SELECT Columns, Values
FROM
(
SELECT TableName, dates, ModelName, BaseUnitPerPallet, pallet
FROM Database
as source_query
)
UNPIVOT
(
Values FOR Columns IN ( TableName, dates, ModelName, BaseUnitPerPallet, pallete)
)
as pivot_results
any advice or guidance would be great.
Additionally, any resource to do this dinamic? and apply the logic without write the column names?
Thanks in advanceĀ”
I'd recommend using APPLY to unpivot your table
Unpivot using APPLY
DROP TABLE IF EXISTS #YourTable
CREATE TABLE #YourTable (
ID INT IDENTITY(1,1) PRIMARY KEY
,TableName VARCHAR(100)
,Dates Varchar(25)
,ModelName VARCHAR(100)
,BaseUnitPerPallet TINYINT
,Pallet TINYINT
)
INSERT INTO #YourTable
VALUES
('Calendar','June',NULL,4,1)
,('Country','June',NULL,2,6)
,('Product','June','DOWNSTREAM',NULL,8)
,('ProductBOM','June','DOWNSTREAM',9,9)
SELECT A.ID,B.*
FROM #YourTable AS A
CROSS APPLY
(VALUES
('TableName',A.TableName)
,('Dates',A.Dates)
,('ModelName',A.ModelName)
,('BaseUnitPerPallet',CAST(A.BaseUnitPerPallet AS Varchar(100)))
,('Pallet',CAST(A.Pallet AS Varchar(100)))
) AS B(ColumnName,Val)
--WHERE B.Val IS NOT NULL /*Optional in case you want to ignore NULLs*/
ORDER BY A.ID,B.ColumnName
My table is:
SBType|SBName|Qty
===================
SMDB SB01 1
SMDB SB01 4
SMDB SB02 2
SMDB SB02 5
SMDB SB03 3
SMDB SB03 6
My desired output is:
SB01 | SB02 | SB03
==================
1 2 3
4 5 6
This is what my code looks like:
SELECT *
FROM (
SELECT
SM.SBName,ISNULL(ES.Qty,0)Qty
FROM RE_ES_SwitchBoard_Mast SM
left outer join RE_ES_Estimations ES on SM.PrCode=ES.PrCode and
Sm.SBType=ES.SBType and SM.SBName=ES.SBName
Where SM.PrCode='PR004' and SM.SBType='SMDB'
) as s
PIVOT
(
Max(Qty)
FOR [SBName] IN (SB01, SB02, SB03)
)AS pvthere
and the result of my attempt looks like:
SB01 SB02 SB03
1 2 3
I have tried with MAX(Qty) but it is not working.
Thanks in advance.
You are almost there.
By adding ROW_NUMBER() OVER (PARTITION BY SBName ORDER BY Qty) rn to the source of PIVOT clause you get multiple rows for different SBName instead of one grouped row. Your query should look like:
SELECT SB01, SB02, SB03
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY SB.SBName ORDER BY Qty) rn,
SB.SBName,ISNULL(ES.Qty,0) Qty
FROM RE_ES_SwitchBoard_Mast SM
left outer join RE_ES_Estimations ES on SM.PrCode=ES.PrCode and
Sm.SBType=ES.SBType and SM.SBName=ES.SBName
Where SM.PrCode='PR004' and SM.SBType='SMDB'
) as s
PIVOT
(
Max(Qty)
FOR [SBName] IN (SB01, SB02, SB03)
)AS pvthere
A verifiable example here:
CREATE TABLE #sample
(
SBType varchar(MAX),
SBName varchar(MAX),
Qty int
)
INSERT INTO #sample VALUES ('SMDB','SB01',1)
INSERT INTO #sample VALUES ('SMDB','SB01',4)
INSERT INTO #sample VALUES ('SMDB','SB02',2)
INSERT INTO #sample VALUES ('SMDB','SB02',5)
INSERT INTO #sample VALUES ('SMDB','SB03',3)
INSERT INTO #sample VALUES ('SMDB','SB03',6)
SELECT SB01, SB02, SB03
FROM (
SELECT
ROW_NUMBER() OVER (PARTITION BY SBName ORDER BY Qty) rn, SBName,ISNULL(Qty,0) Qty
FROM #sample
) as s
PIVOT
(
Max(Qty)
FOR [SBName] IN (SB01, SB02, SB03)
) AS pvthere
DROP TABLE #sample
Dynamic query is the only way to use varchar columns in pivot. Have a look at below code to get idea.
First step is to generate comma separated list of items for column you need to use in pivot.
Then you can use this generated list in dynamic query for pivot columns.
Note: For example purpose I have used temp table. Replace it with your actual table.
CREATE TABLE #temptable
(
SBType VARCHAR(20),
SBName VARCHAR(20),
Qty INT
)
INSERT INTO #temptable SELECT 'SMDB','SB01',1
INSERT INTO #temptable SELECT 'SMDB','SB01',4
INSERT INTO #temptable SELECT 'SMDB','SB02',2
INSERT INTO #temptable SELECT 'SMDB','SB02',5
INSERT INTO #temptable SELECT 'SMDB','SB03',3
INSERT INTO #temptable SELECT 'SMDB','SB03',6
SELECT * FROM #temptable
DECLARE #cols AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(SBName)
from #temptable
group by SBName
order by SBName
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #cols
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT *
FROM
(
SELECT SBType,SBName,Qty,
row_number() over (partition by SBName order by Qty) as rn
FROM #temptable
) src
PIVOT
(
MIN(Qty)
FOR SBName IN (' + #cols + ')
) piv;'
EXEC(#query)
DROP TABLE #temptable
I have the following scenario:
Generation of a pivot with dynamic columns which I can manage via generating dynamic sql either on the client or in a stored procedure
I then need to calculate additional values based on the values already calculated by the pivot.
Here is the sql to generate all the steps in the process :
IF OBJECT_ID('dbo.departmentStats', 'U') IS NOT NULL
DROP TABLE dbo.departmentStats;
CREATE TABLE departmentStats
([Facility] varchar(50), [Department] varchar(50),[Stat] varchar(5),
[January] int, [February] int, [March] int);
INSERT INTO departmentStats
([Facility],[Department],[Stat], [January], [February], [March])
VALUES
('f1','d1','Stat1', 90, 40, 60),
('f1','d1','Stat2', 30, 20, 10);
select 'Original Data' as src,* from departmentStats
IF OBJECT_ID('tempdb.dbo.#pivotstats', 'U') IS NOT NULL
DROP TABLE #pivotstats;
CREATE TABLE #pivotstats
(facility varchar(50),department varchar(50),stat VARCHAR(50),period
varchar(50),value int)
insert into #pivotstats
select facility,department,Stat, period, value
from departmentStats
unpivot
(
value
for Period in (January, February, March)
) u
select 'Original after unpivot' as src,* from #pivotstats
IF OBJECT_ID('dbo.departmentStats2', 'U') IS NOT NULL
DROP TABLE dbo.departmentStats2;
CREATE TABLE departmentStats2
([Facility] varchar(50), [Department] varchar(50),[Period] varchar(20),
[stat1] int, [stat2] int, [Sum] numeric(10,2),[Division] numeric(10,2));
insert into departmentStats2
select
facility
,department
,period
,Stat1
,stat2
,Stat1+Stat2 as [sum]
,case when Stat2<>0 then cast(Stat1/Stat2 AS numeric) else 0.0 end as
division
from #pivotstats
Pivot(
sum(value)
for Stat in ([Stat1],[Stat2])
)
as x
select 'Added formula columns' as src,* from departmentStats2
select 'Union and repivot' as src,* from (
select
facility
,department
,Period
,'Stat1' as Stat
,stat1 as value
from departmentStats2
union all
select
facility
,department
,Period
,'Stat2' as Stat
,stat2 as value
from departmentStats2
union all
select
facility
,department
,Period
,'sum' as Stat
,[SUM] as value
from departmentStats2
union all
select
facility
,department
,Period
,'Division' as Stat
,[Division] as value
from departmentStats2
) as bunion
pivot(
sum(value)
for Period in (January, February, March)
)as P
I have only included three periods for the sample.
I have no doubt that I can generate SQL in this format at will.
I don't foresee any real issues considering my data source will be static (updated daily) and heavily indexed. I don't yet have a full data set ready to test but I will update the q when I do
The reason for the pivot olympics is that the final output is actually as spreadsheet which uses index/match to lookup the values for each stat by facility/department/name to produce graphs and charts
Opinions ?
Obvious flaws?
Is this better done in C# by generating a class at runtime?
Remember the idea is to provide the ability to add stats based on known stats with a minimum of effort.
Here is a better way to do the last step using cross apply instead of union all
select 'Union and repivot' as src,* from (
select
departmentStats2.Facility,
departmentStats2.Department,Departmentstats2.period,x.stat,x.value
from
departmentStats2
cross Apply(
values(Facility,Department,Period,'1_Sales',Sales),
(Facility,Department,Period,'2_Cost',Cost),
(Facility,Department,Period,'3_GrossProfit',GrossProfit),
(Facility,Department,Period,'4_GPP',GPP)
) as x(Facility,Department,Period,Stat,[Value])
)as P
pivot(
sum(value)
for Period in (January, February, March)
)as P
order by Facility,department,Stat
from
http://sqlsunday.com/2014/03/02/unpivot-using-cross-apply/
I am trying to Pivot this table whose name is #salida
IDJOB NAME DATE
1 Michael NULL
1 Aaron NULl
THe result which I want to obtain is
IDJOB DATE NAME1 NAME2
1 NULL Michael Aaron
My code is this
SELECT *
FROM #salida
PIVOT
(
MAX([Name]) FOR [Name] IN ([Name1],[Name2])
) PVT GROUP BY IdJob,Date,Name1,Name2 ;
SELECT * FROM #salida
The result which obtain is
IDJOB DATE NAME1 NAME2
1 NULL NULL NULL
#XabiIparra, see a mock up. you need to partition by the IdJob and then add the columns needed.
DECLARE #salida TABLE(idjob VARCHAR(100),[Name] VARCHAR(100),[DATE] DATE);
INSERT INTO #salida VALUES
(1,'Michael', NULL)
,(1,'Aaron', NULL)
,(2,'Banabas', NULL)
SELECT p.*
FROM
(
SELECT *
,'NAME'+CAST(ROW_NUMBER() OVER(PARTITION BY [idjob] ORDER BY NAME) AS varchar(100)) ColumnName
FROM #salida
)t
PIVOT
(
MAX([Name]) FOR ColumnName IN (NAME1,NAME2,NAME3,NAME4,NAME5 /*add as many as you need*/)
)p;
How about must using aggregation and min() and max()?
select idjob, date, min(name), max(name)
from #salida
group by idjob, date;
SQL tables represent unordered sets, so there is no ordering to the values (unless another column specifies the ordering). So, this is probably the simplest way to get two different values in the same row.