I've got a set of data that looks something like this:-
product May_Qty June_Qty
--------- --- -----------
p1 2 44
p2 1 54
p3 5 55
i want the result like: (using pivot) or other methods
product Month Qty
--------- --- -----------
p1 May 2
p1 June 44
p2 May 1
p2 June 54
p3 May 5
p3 June 55
I must admit: The whole design smells a bit. Normally it is the other way round: Data is in a list and people want it as pivoted (wide) list for displaying purpose. So consider to work with a table with the design you want as target at the moment...
If you really want to stick with this, here are two approaches which produce the same output:
DECLARE #tbl TABLE(product VARCHAR(100),May_Qty INT,June_Qty INT);
INSERT INTO #tbl VALUES
('p1',2,44)
,('p2',1,54)
,('p3',5,55);
With UNION ALL you create a derived table with the values as list and then you sort it
SELECT product,[Month],Qty
FROM
(
SELECT product,5 AS MonthIndex,'May' AS [Month],May_Qty As Qty
FROM #tbl
UNION ALL
SELECT product,6,'June',June_Qty
FROM #tbl
) AS parted
ORDER BY product,MonthIndex;
UNPIVOT does roughly the same:
SELECT up.*
FROM
(SELECT product, May_Qty AS May, June_Qty AS June FROM #tbl) AS tbl
UNPIVOT
(Qty FOR [Month] IN(May,June)) AS up
Related
I am trying to do a simple query in Oracle SQL using Pivot. I have 12 columns in my table, but only the first four are of interest. The columns are "FACILITY_ID" (Unique Identifier), "REPORTING_YEAR" (Year data was reported), "SUBPART" (Category of data wanting to pivot by - values acceptable between A and Z), and "CO2E" (floating point number reported). I want to take only the data from subparts C and K (the third column) and add them up into their own columns.
For example:
If my original table looks like:
FACILITY_ID --- REPORTING_YEAR --- SUBPART --- CO2E
10 -------------- 2020 ---------------------- C -------- 10
11 -------------- 2020 ---------------------- K -------- 20
10 -------------- 2020 ---------------------- K -------- 40
10 -------------- 2020 ---------------------- K -------- 40
11 -------------- 2020 ---------------------- C -------- 30
I would like to get something like:
FACILITY_ID --- REPORTING_YEAR ----- C ----- K
10 -------------- 2020 ----------------- 10 ----- 80
11 -------------- 2020 ----------------- 30 ----- 20
My code as of now is as follows:
Create Table CandK_emissions as
Select
FACILITY_ID,
REPORTING_YEAR,
SUBPART,
CO2E
From
facilityReport
Pivot
(
Sum(CO2E)
For SUBPART
in ('C',
'K')
)
The error I'm getting is 'Ora-00904: "CO2e": Invalid Identifier'. I've double checked that everything is spelled correctly. I'm not sure where I'm going wrong.
The SELECT clause must show what columns will exist in the output, not what columns are used from the base table. In your query, you are aggregating the CO2E values, separately for different values of SUBPART. The result of pivoting doesn't have CO2E values anymore, or SUBPART values; instead, the two SUBPART values you are interested in, C and K, become two distinct columns in the output, and the sums of CO2E appear in these two new columns.
Your query should SELECT columns C and K; the error message is telling you that after pivoting, there is no CO2E column to select. (After you change that, it would tell you the same thing about SUBPART.)
Here is how this should look. Note a few things: In the "test data" I simulated one more column, a primary key named PK, to demonstrate that you must EXCLUDE it first, in an inline view (the sub-SELECT in the FROM clause). Also note that, to make the PIVOT as efficient as possible, in the subquery I only select the rows we need - those where the SUBPART is either C or K. We don't need to see the other rows.
The WITH clause is just for testing - remove it, and use your actual table and column names in the query.
with
test_data (pk, facility_id, reporting_year, subpart, co2e) as (
select 335, 10, 2020, 'C', 10 from dual union all
select 440, 11, 2020, 'K', 20 from dual union all
select 482, 10, 2020, 'K', 40 from dual union all
select 106, 10, 2020, 'K', 40 from dual union all
select 476, 11, 2020, 'C', 30 from dual
)
-- end of test data; actual query begins below this line
select facility_id, reporting_year, c, k
from (
select facility_id, reporting_year, subpart, co2e
from test_data
where subpart in ('C', 'K')
)
pivot (sum(co2e) for subpart in ('C' as c, 'K' as k))
order by facility_id, reporting_year -- or whatever is needed
;
FACILITY_ID REPORTING_YEAR C K
----------- -------------- ---------- ----------
10 2020 10 80
11 2020 30 20
Note - it may be simpler (and more efficient) to do away with PIVOT altogether, and to "pivot" the old way, using conditional aggregation (the way pivoting was done before the PIVOT operator was introduced). Something like this:
select facility_id, reporting_year,
sum(case subpart when 'C' then co2e end) as c,
sum(case subpart when 'K' then co2e end) as k
from test_data
group by facility_id, reporting_year
order by facility_id, reporting_year
;
I need to search for a value between two strings that are varchar.
I have two tables:
#Code:
StartList EndList Code
1 3 A
4 7 B
20 25 C
1a 1e 1
#Product:
Product
22
2
1c
If I search for product 22 between startlist and end list then I will get two results:
StartList EndList Code Product
1 3 A 22
20 25 C 22
Since its a varchar value, it searched for every string individually. 2 of 22 is between the first row above and 22 is between 20 and 25 on 2nd row. I cannot change the columns to string because it has a varchar value that needs to be search as well. For example: Product 1c should be found in row four of table #code. Any advice on how I can accomplish this so I only get the exact result: Product 22 between 20 and 25, product 2 between 1 and 3, and product 1c between 1a and 1e?
Here is the code I am using:
IF OBJECT_ID('tempdb..#Code') IS NOT NULL DROP TABLE #Code
CREATE TABLE #Code (
StartList VARCHAR(10)
,EndList VARCHAR(10)
,Code VARCHAR(10))
INSERT INTO #Code(StartList, EndList, Code)
VALUES('1','3','A'),('4','7','B'),('20','25','C'),('1a','1e','1')
IF OBJECT_ID('tempdb..#Product') IS NOT NULL DROP TABLE #Product
CREATE TABLE #Product (
Product VARCHAR(10))
INSERT INTO #Product(Product)
VALUES('22'),('2'),('1c')
--SELECT * FROM #Code
--SELECT * FROM #Product
SELECT *
FROM #code a
left join #product b on b.product between a.startlist and a.endlist
where product = '22'
I recommend fixing the data to zero-pad the numbers so the values can be correctly compared as strings.
Absent that, though, you could try converting them to numbers:
select *
from #code c join
#product p
on try_convert(int, p.product) between try_convert(int, c.startlist and try_convert(int, c.endlist) or
(try_convert(int, c.startlist) is null and
p.product between c.startlist and c.endlist)
where p.product = '22'
I've looked at some answers but none of them seem to be applicable to me.
Basically I have this result set:
RowNo | Id | OrderNo |
1 101 1
2 101 10
I just want to convert this to
| Id | OrderNo_0 | OrderNo_1 |
101 1 10
I know I should probably use PIVOT. But the syntax is just not clear to me.
The order numbers are always two. To make things clearer
And if you want to use PIVOT then the following works with the data provided:
declare #Orders table (RowNo int, Id int, OrderNo int)
insert into #Orders (RowNo, Id, OrderNo)
select 1, 101, 1 union all select 2, 101, 10
select Id, [1] OrderNo_0, [2] OrderNo_1
from (
select RowNo, Id, OrderNo
from #Orders
) SourceTable
pivot (
sum(OrderNo)
for RowNo in ([1],[2])
) as PivotTable
Reference: https://learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot?view=sql-server-2017
Note: To build each row in the result set the pivot function is grouping by the columns not begin pivoted. Therefore you need an aggregate function on the column that is being pivoted. You won't notice it in this instance because you have unique rows to start with - but if you had multiple rows with the RowNo and Id you would then find the aggregation comes into play.
As you say there are only ever two order numbers per ID, you could join the results set to itself on the ID column. For the purposes of the example below, I'm assuming your results set is merely selecting from a single Orders table, but it should be easy enough to replace this with your existing query.
SELECT o1.ID, o1.OrderNo AS [OrderNo_0], o2.OrderNo AS [OrderNo_1]
FROM Orders AS o1
INNER JOIN Orders AS o2
ON (o1.ID = o2.ID AND o1.OrderNo <> o2.OrderNo)
From your sample data, simplest you can try to use min and MAX function.
SELECT Id,min(OrderNo) OrderNo_0,MAX(OrderNo) OrderNo_1
FROM T
GROUP BY Id
I have a simple table from a select query that looks like this
CATEGORY | EQUAL | LESS | GREATER
VALUE | 60 | 100 | 20
I want to be able to transpose it so it looks like this
CATEGORY | VALUE
EQUAL | 60
LESS | 100
GREATER | 20
I tried using the pivot function in oracle but I can't seem to get it to work.
I've tried looking all over online but I can't find anything that will help me.
Any help is much appreciated thank you!
Using unpivot -
CREATE TABLE Table1
(CATEGORY varchar2(5), EQUAL int, LESS int, GREATER int)
;
INSERT ALL
INTO Table1 (CATEGORY, EQUAL, LESS, GREATER)
VALUES ('VALUE', 60, 100, 20)
SELECT * FROM dual
;
Query -
select COL AS CATEGORY,VALUE from table1
unpivot (value for COL in (EQUAL, LESS, GREATER));
Result -
CATEGORY VALUE
EQUAL 60
LESS 100
GREATER 20
You can use union all:
select 'EQUAL' as category, equal as value from t union all
select 'LESS' as category, less from t union all
select 'GREATER' as category, greater from t;
If you had a large table, you might want to try some other method (such as a lateral join in Oracle 12c). But for a small table, this is fine.
You may unpivot your values by contribution of DECODE and CONNECT BY clauses :
select decode(myId, 1, 'EQUAL',
2, 'LESS',
3, 'GREATER') as category,
decode(myId, 1, EQUAL,
2, LESS,
3, GREATER) as value
from mytable
cross join (select level as myId from dual connect by level <= 3);
CATEGORY VALUE
-------- -----
EQUAL 60
LESS 100
GREATER 20
SQL Fiddle Demo
I have several tables all holding small amounts of data on a batch of product. For example, I have a table (called 'Tests') that holds a test number, a test name and the description. This is referenced by my batch table, which holds a test number, test result (as a real) and the batch number itself.
Some batches may have 50 tests, some may have 30, some may have as little as 1.
I was hoping to create a view that converts something like these tables;
BatchNumber TestNum TestResult | TestNumber TestName TestDesc
----------- -------- ----------- | ----------- --------- ---------
1000 1 1.20 | 1 Thickness How thick the product is
1001 1 1.30 | 2 Colour What colour the product is
1001 2 45.1 | 3 Weight How heavy the product is
...
to the following;
BatchNumber Thickness Colour Weight
------------ --------- ------ -------
1000 1.20 NULL NULL
1001 1.30 45.1 NULL
...
Though the 'null' could just be blank, it would probably be better that way, I just used that to better show my requirement.
I've found many articles online on the benefit of PIVOTing, UNPIVOTing, UNIONing but none show the direct benefit, or indeed provide a clear and succinct way of using the data without copying data into a new table, which isn't really useful for my need. I was hoping that a view would be possible so that end-user applications can just call that instead of doing the joins locally.
I hope that makes sense, and thank you!
You need cross tab query for this.
http://www.mssqltips.com/sqlservertip/1019/crosstab-queries-using-pivot-in-sql-server/
DECLARE #Tests Table (TestNumber int, TestName VARCHAR(100),TestDesc varchar(100))
INSERT INTO #Tests
SELECT 1, 'Thickness', '' UNION ALL
SELECT 2, 'Color', '' UNION ALL
SELECT 3, 'Weight', ''
DECLARE #BTests Table (BatchNum int, TestNumber int, TestResult float)
INSERT INTO #BTests
SELECT 1000, 1, 1.20 UNION ALL
SELECT 1001, 1, 1.30 UNION ALL
SELECT 1001, 2, 45.1
;with cte as (
select b.*, t.TestName
from #BTests b
inner join #Tests t on b.TestNumber = t.TestNumber
)
SELECT Batchnum, [Thickness] AS Thickness, [Color] AS Color, [Weight] as [Weight]
FROM
(SELECT Batchnum, TestName, testResult
FROM Cte ) ps
PIVOT
(
SUM (testResult)
FOR testname IN
( [Thickness],[Color], [Weight])
) AS pvt
CREATE VIEW?
e.g.
CREATE VIEW myview AS
SELECT somecolumns from sometable