How to pivot 2 columns into one row - sql

I am trying to pivot a table that has both Units and Base Units for a certain product. I am trying to make my end result one line only.
Product Unit BaseUnit
Gas MMcf Mcf
Oil Mbbl bbl
Water Mgal gal
My output table should look like this:
GasUnit GasBaseUnit OilUnit OilBaseUnit WaterUnit WaterBaseUnit
MMcf Mcf Mbbl bbl Mgal gal
I have done a pivot table before but never had to pivot 2 columns at the same time and move them into one row.
Here is what I have so far. Can I use 2 aggregates? I am not sure how to approach this.
SELECT *
from
(
select Product, Unit, BaseUnit
from t
) x
pivot
(
sum(BaseUnit)
for Product in ([Gas], [Oil], [Water])
) p

With static data this will get your output table
WITH prep AS (
SELECT Product + ' Unit' TYPE, Unit Value
FROM utilities
UNION ALL
SELECT Product + ' BaseUnit' TYPE, BaseUnit Value
FROM utilities
)
SELECT [Gas Unit], [Gas BaseUnit]
, [Oil Unit], [Oil BaseUnit]
, [Water Unit], [Water BaseUnit]
FROM (SELECT TYPE, Value
FROM prep
) a
PIVOT
(MAX(Value)
FOR TYPE IN ([Gas Unit], [Gas BaseUnit]
, [Oil Unit], [Oil BaseUnit]
, [Water Unit], [Water BaseUnit])
) pvt
Demo: SQLFiddle
With dynamic data you'll need to use a dynamic query to create the PIVOT columns list

Related

convert data from multiple columns into single row sorting descending

I am trying to query the original source which contain totals from a category (in this case Vehicles) into the second table.
Motorcycle
Bicycle
Car
1
3
2
Desired Output:
Vehicle
Quantity
Bicycle
3
Car
2
Motorcycle
1
Additionally, I need that the Quantity is sorted in descending order like showing above.
So far I have tried to do an Unpivot, but there is a syntax error in the Unpivot function. Is there another way to reach out the same results?
My code so far:
SELECT Vehicle_Name
FROM
(
SELECT [Motorcycle], [Bycycle], [Car] from Data
) as Source
UNPIVOT
(
Vehicle FOR Vehicle_Name IN ([Motorcycle], [Bycycle], [Car])
) as Unpvt
Edit: Added sort requirement.
You can use CROSS APPLY here too
select vehicle, amnt
from test
cross apply(
VALUES('motorcycle', motorcycle)
,('bicycle', bicycle)
,('car', car)) x (vehicle, amnt)
order by amnt desc
Fiddle here
Try this
with data1 as
(
Select * from data)
Select * From
(
Select 'motorcycle' as "Vehicle", motorcycle as quantity from data1
union all
Select 'bicycle' , bicycle from data1
union all
Select 'car', car from data1
) order by quantity desc;
Since we don't know what DBMS, here's a way that'd work in the one I use the most.
SELECT *
FROM (SELECT map_from_entries(
ARRAY[('Motorcycle', Motorcycle),
('Bicycle', Bicycle),
('Car', Car)])
FROM Source) AS t1(type_quant)
CROSS JOIN UNNEST(type_quant) AS t2(Vehicle, Quantity)
ORDER BY Quantity DESC
-Trino

How to make rows into columns in SQL

I have this table
SELECT PolicyID, ItemID, Period, Inventory1, Inventory2
FROM tblInventory
I want to convert this table into this:
The period will be converted as Column such as Inventory1 -1 and Inventory2 -1 until 4th period, per period there are two columns included: inventory1 and inventory2.
I would like to ask help on how to code this in SQL. Thank you!
To use PIVOT with your example you want to UNPIVOT the data first.
SELECT
*
FROM
(
SELECT
UP.PolicyId
, UP.ItemId
, CONCAT(UP.Inventories, '-', UP.Period) AS Inventories
, UP.Inventory
FROM
tblInventory AS TI
UNPIVOT
(
Inventory FOR Inventories IN (Inventory1, Inventory2)
) AS UP
) AS UNP
PIVOT
(
MAX(Inventory)
FOR Inventories IN
(
[Inventory1-1], [Inventory1-2], [Inventory1-3], [Inventory1-4]
, [Inventory2-1], [Inventory2-2], [Inventory2-3], [Inventory2-4]
)
) AS PVT

SQL pivot / VLOOKUP query

I have the following simplified table so each stock code has
multiple warehouses and I want to "pivot" it so I can get
the cost for each warehouse just in 1 line for the stockcode
Stockcode | Warehouse | Cost
A100 WH 100$
A100 ZZ 200$
What I would like to have is the following.
So only 1 stockcode line with the warehouse costs pivoted.
Stockcode | Cost WH | Cost ZZ
A100 100$ 200$
I currently did it by exporting it to excell, creating a new sheet and add a new column to the sheet using a VLOOKUP to the main table and add the ZZ cost like that.
How would you turn this around in SQL? I am a bit stuck with understanding how to transform this tabular data in such a way.
Here's how to do this query using PIVOT:
select Stockcode, [WH] as CostWH, [ZZ] as CostZZ
from (
select Stockcode, Warehouse, Cost
from MyTable
) p
pivot (
MAX(Cost)
for Warehouse in ([WH], [ZZ])
) as pvt
order by Stockcode;
Test it on SQLFiddle
I think (Stockcode,Warehouse) is unique in your table.
And I think you can use PIVOT like it
SELECT Stockcode,[WH],[ZZ]
FROM TestData PIVOT(MAX(Cost) FOR Warehouse IN([WH],[ZZ])) p
And use dynamic query for generate query for all the warehouses
DECLARE #Warehouses varchar(500)=''
SELECT #Warehouses+=CONCAT(',[',Warehouse,']')
FROM
(
SELECT DISTINCT Warehouse
FROM TestData
) q
ORDER BY Warehouse
SET #Warehouses=STUFF(#Warehouses,1,1,'')
PRINT #Warehouses
DECLARE #query varchar(2000)=CONCAT('SELECT Stockcode,',#Warehouses,'
FROM TestData PIVOT(MAX(Cost) FOR Warehouse IN(',#Warehouses,')) p')
PRINT #query
EXEC(#query)
My another answer similar to it - Display count results of requests with results of jobs horizontally and locations vertically 3 tables
However, you could also do that by using simple case expression if you don't want to go pivot or dynamic pivot
SELECT
Stockcode ,
MAX( CASE (Warehouse) WHEN 'WH' THEN Cost END)[Cost WH],
MAX(CASE (Warehouse) WHEN 'ZZ' THEN Cost END) [Cost ZZ]
FROM <table> GROUP BY Stockcode
Dynamic pivot way :
DECLARE #Col nvarchar(max), #query nvarchar(max)
select #Col = STUFF(
(SELECT ',' +QUOTENAME(Warehouse) FROM <table> FOR XML PATH('')),
1, 1, ''
)
SELECT #query = N'select Stockcode, [WH] as CostWH, [ZZ] as CostZZ
from (
select Stockcode, Warehouse, Cost
from <table>) p
pivot (max(Cost) for Warehouse in ('+#Col+')
) as pvt order by Stockcode;'
exec(#query)
Result :
Stockcode Cost WH Cost ZZ
A100 100$ 200$

Unpivot Data with Multiple Columns - Syntax Help Please

I have the following data in which I would like to unpivot
I created this query to unpivot the 'Actual' rows but can't seem to figure out the syntax for unpivoting the 'Plan' and 'PriorYear' as well.
SELECT FiscalYear, Period, MetricName, ActualValue
FROM vw_ExecSummary
UNPIVOT
(ActualValue FOR MetricName IN ( [Net Revenue], [Total C.S. Salaries]
)) AS unpvt
WHERE [Type] = 'Actual'
The unpivoted data looks like this but I want to also add the Plan and PriorYear columns to the right of the ActualValue column below
Any help would be greatly appreciated. Thanks.
I can't test this at the moment, but I think it works like this. First, you need to UNPIVOT all the data:
SELECT fiscalYear, period, type, metricName, metricValue
FROM vw_ExecSummary
UNPIVOT (metricValue FOR metricName IN ([Net Revenue], [Total C.S. Salaries])) unpvt
Which should result in a table that looks something like this:
fiscalYear period type metricName metricValue
===================================================================
15 1 'Actual' 'Net Revenue' 3676798.98999997
15 1 'Actual' 'Total C.S. Salaries' 1463044.72
15 1 'Plan' 'Net Revenue' 3503920.077405
...................... (remaining rows omitted)
We could then PIVOT the rows as normal to get the new columns (that's what it's for):
SELECT fiscalYear, period, metricName,
[Actual] AS actualValue, [Plan] AS planValue, [PriorYear] AS priorYearValue
FROM <previous_data>
PIVOT (SUM(metricValue) FOR (type IN ([Actual], [Plan], [PriorYear]) pvt
(the SUM(...) shouldn't actually do anything here, as presumable the other columns comprise a unique row, but we're required to use an aggregate function)
...which should yield something akin to the following:
fiscalYear period metricName actualValue planValue priorYearValue
======================================================================================
15 1 'Net Revenue' 3676798.98999997 3503920.077405 40436344.4499999
...................................... (remaining rows omitted)
So putting it together would look like this:
SELECT fiscalYear, period, metricName,
[Actual] AS actualValue, [Plan] AS planValue, [PriorYear] AS priorYearValue
FROM (SELECT fiscalYear, period, type, metricName, metricValue
FROM vw_ExecSummary
UNPIVOT (metricValue FOR metricName IN ([Net Revenue], [Total C.S. Salaries])) unpvt) unpvt
PIVOT (SUM(metricValue) FOR type IN ([Actual], [Plan], [PriorYear])) AS pvt
SQL Fiddle Example
I have just one concern, though: values like 3676798.98999997, 3503920.077405, etc, make me think those columns are floating point (ie, REAL or FLOAT),but the values are named for monetary uses. If this is the case.... you are aware floating-point values can't store things like .1 exactly, right (ie, you can't actually add a dime to a value)? And that, when values get large enough, you can't add 1 anymore either? Usually when dealing with monetary values you should be using something based on a fixed-point type, like DECIMAL or NUMERIC.
This is a situation for Itzig Ben-Gan's cross apply values pivoting:
create table #data (FiscalYear smallint, Period tinyint, ValueType nvarchar(25), NetRevenue float, Salaries float);
insert into #data values
(15,1,N'Actual',3676798.98999,1463044.71999),
(15,1,N'Plan',3503920.977405,1335397.32878),
(15,1,N'PriorYear',4043634.449,1543866.89);
select d.FiscalYear, d.Period,
ActualNetRevenue = sum(v.ActualNetRevenue), ActualSalaries = sum(v.ActualSalaries),
PlanNetRevenue = sum(v.PlanNetRevenue), PlanSalaries = sum(v.PlanSalaries),
PriorYearNetRevenue = sum(v.PriorYearNetRevenue), PriorYearSalaries = sum(v.PriorYearSalaries)
from #data d
cross apply
(values
(N'Actual',d.NetRevenue,d.Salaries,0,0,0,0),
(N'Plan',0,0,d.NetRevenue,d.Salaries,0,0),
(N'PriorYear',0,0,0,0,d.NetRevenue,d.Salaries))
v (ValueType, ActualNetRevenue, ActualSalaries, PlanNetRevenue, PlanSalaries, PriorYearNetRevenue, PriorYearSalaries)
where d.ValueType = v.ValueType
group by d.FiscalYear, d.Period;
drop table #data;

Access 2010 Crosstab Query Expression--in One Query

I would like to add this expression:
([2013]/[2012]-1) AS [Change%]
As a field to the crosstab query below:
TRANSFORM
Sum(Data.Spending)
SELECT
Data.Category
FROM
Data
WHERE
(((Data.Year)="2012" Or (Data.Year)="2013"))
GROUP BY
Data.Category
PIVOT
Data.Year;
This is solved through using another table in this thread: Access 2007 Crosstab Query Expression
But for my purposes I need to have everything together in one query.
This is because I am writing SQL in another program, http://www.ljzsoft.com/ppt-report.htm, which uses the query to directly access an Access database.
As you have probably discovered, Access won't let us use a Crosstab query as a subquery. If we try to do
SELECT ...
FROM
(
TRANSFORM
we get "Syntax error in FROM clause". One workaround is to do all of the aggregations, create the derived (calculated) values, UNION them together, and then "crosstab" that. In your case:
TRANSFORM Sum(ColValue) AS SumOfColValue
SELECT Category
FROM
(
SELECT Category, [Year] AS ColHead, Sum(Spending) AS ColValue
FROM Data
WHERE [Year] IN ("2012", "2013")
GROUP BY Category, [Year]
UNION ALL
SELECT
curr.Category,
"Change%" AS ColHead,
(curr.SumOfSpending/prev.SumOfSpending-1) AS ColValue
FROM
(
SELECT Category, [Year], Sum(Spending) AS SumOfSpending
FROM Data
WHERE [Year] IN ("2012", "2013")
GROUP BY Category, [Year]
) AS curr
INNER JOIN
(
SELECT Category, [Year], Sum(Spending) AS SumOfSpending
FROM Data
WHERE [Year] IN ("2012", "2013")
GROUP BY Category, [Year]
) AS prev
ON prev.Category = curr.Category
AND CLng(prev.[Year]) = (CLng(curr.[Year]) - 1)
)
GROUP BY Category
PIVOT ColHead
which, for my sample data, returns
Category 2012 2013 Change%
--------- ---- ---- -----------------
Category1 123 345 1.80487804878049
Category2 234 456 0.948717948717949
If that is too nasty for your liking then you might want to investigate whether your reporting tool supports calculated report fields (e.g., in Crystal Reports I believe they are called "Formula Fields").