I request your collaboration because pivot on a table and separating the records by null, but still leave the fields at 0 with NVL
Table
product | value
----------+-------
Shirts | 1200
Caps | 0
Stocks | 0
Glasses | 100
Shoes | 0
Código pivot
select * from products
PIVOT (sum(value)
for titles in ('product', 'value')) AS pivot_product
Result:
product | Shirts | Caps | Stocks | Glasses | Shoes
---------+-----------+--------+-------------+---------+----------
value | NULL | NULL | NULL | 100 | NULL
value | 1200 | NULL | NULL | NULL | NULL
Expected result:
product | Shirts | Caps | Stocks | Glasses | Shoes
---------+-----------+--------+-------------+-------+----------
valor | 1200 | NULL | NULL | 100 | NULL
Optional
product | Shirts | Caps | Stocks | Glasses | Shoes
---------+-----------+--------+-------------+-------+----------
valor | 1200 | 0 | 0 | 100 | 0
You need to put the column values in the pivot list:
Oracle Setup:
CREATE TABLE test_data ( product, value ) AS
SELECT 'Shirts', 1200 FROM DUAL UNION ALL
SELECT 'Caps', 0 FROM DUAL UNION ALL
SELECT 'Stocks', 0 FROM DUAL UNION ALL
SELECT 'Glasses', 100 FROM DUAL UNION ALL
SELECT 'Shoes', 0 FROM DUAL
Query:
SELECT 'value' AS product,
p.*
FROM test_data
PIVOT ( SUM( value ) FOR product IN (
'Shirts' AS Shirts,
'Caps' AS Caps,
'Stocks' AS Stocks,
'Glasses' AS Glasses,
'Shoes' AS Shoes
) ) p
Output:
PRODUCT | SHIRTS | CAPS | STOCKS | GLASSES | SHOES
:------ | -----: | ---: | -----: | ------: | ----:
value | 1200 | 0 | 0 | 100 | 0
db<>fiddle here
Just use conditional aggregation. It is more flexible:
select 'valor' as product,
sum(case when product = 'Shirts' then value end) as shirts,
sum(case when product = 'Caps' then value end) as caps,
sum(case when product = 'Stocks' then value end) as stockes,
sum(case when product = 'Shirts' then value end) as shirts,
sum(case when product = 'Glasses' then value end) as glasses,
sum(case when product = 'Shoes' then value end) as shoes
from test_data;
Related
how to capture the sum of null of an attribute(bit_id) by date and company
If what you mean is you want to count how many values are NULL for each date/company, then you can just use a CASE statement wrapped in a SUM:
declare #dataTable table (
recordDate date,
company varchar(100),
attribute bit
)
insert into #dataTable values
('2021-09-28','CompanyA',null),
('2021-09-28','CompanyA',null),
('2021-09-28','CompanyA',1),
('2021-09-28','CompanyB',0),
('2021-09-28','CompanyB',null),
('2021-09-29','CompanyA',0),
('2021-09-29','CompanyB',1),
('2021-09-29','CompanyA',null),
('2021-09-29','CompanyB',null),
('2021-09-29','CompanyB',null),
('2021-09-29','CompanyB',null)
select
recordDate,
company,
sum(case when attribute is null then 1 else 0 end) as countNULLs
from #dataTable
group by recordDate, company
order by recordDate, company
Results:
/------------------------------------\
| recordDate | company | countNULLs |
|------------|----------|------------|
| 2021-09-28 | CompanyA | 2 |
| 2021-09-28 | CompanyB | 1 |
| 2021-09-29 | CompanyA | 1 |
| 2021-09-29 | CompanyB | 3 |
\------------------------------------/
Say I have a table like:
| id | brand | fuel | mpg |
|:--:|:------:|:------:|:---:|
| 1 | ford | diesel | 14 |
| 1 | ford | gas | 20 |
| 1 | toyota | diesel | 30 |
| 1 | toyota | gas | 35 |
and I wish to pivot the columns such that the result is like:
| id | ford | toyota | toyota_mpg | ford_mpg |
|:--:|:------:|--------|:----------:|:--------:|
| 1 | diesel | diesel | 30 | 14 |
| 1 | gas | gas | 35 | 20 |
| 1 | diesel | gas | 35 | 14 |
| 1 | gas | diesel | 30 | 20 |
So far, I have
SELECT id,
MAX(CASE WHEN end_use = 'ford' THEN fuel ELSE NULL END) ford,
SUM(CASE WHEN end_use = 'ford' THEN mpg ELSE NULL END) ford_mpg,
MAX(CASE WHEN end_use = 'toyota' THEN fuel ELSE NULL END) toyota,
SUM(CASE WHEN end_use = 'toyota' THEN mpg ELSE NULL END) toyota_mpg,
FROM table GROUP BY id, fuel
which results below, giving me the correct result for when the fuels align:
| id | ford | toyota | toyota_mpg | ford_mpg |
|:--:|:------:|--------|:----------:|:--------:|
| 1 | diesel | diesel | 30 | 14 |
| 1 | gas | gas | 35 | 20 |
But I am not able to get the combinations of fuels (where they mismatch).
Try below
select id,
t1.fuel ford,
t2.fuel toyota,
t1.mpg ford_mpg,
t2.mpg toyota_mpg
from data t1
join data t2
using (id)
where t1.brand < t2.brand
if applied to sample data in your question - output is
You can explore the pivot operator from the big query. Though I am not sure about your use-case to find out sum/avg/max/min on id level!
WITH
result AS (
SELECT
1 AS id,
'ford' AS brand,
'diesel' AS fuel,
14 AS mpg
UNION ALL
SELECT
1 AS id,
'ford' AS brand,
'gas' AS fuel,
20 AS mpg
UNION ALL
SELECT
1 AS id,
'toyota' AS brand,
'diesel' AS fuel,
30 AS mpg
UNION ALL
SELECT
1 AS id,
'toyota' AS brand,
'gas' AS fuel,
35 AS mpg ),
pivot_result AS (
SELECT
id,
ford,
toyota,
mpg_ford,
mpg_toyota
FROM (
SELECT
*
FROM (
SELECT
id,
fuel,
brand brand_,
brand,
mpg
FROM
result ) PIVOT ( AVG(mpg) mpg FOR brand IN ('ford',
'toyota')) ) PIVOT (MAX(fuel) FOR brand_ IN ('ford',
'toyota')) )
SELECT
f.id,
f.ford,
t.toyota,
t.mpg_toyota,
f.mpg_ford
FROM
pivot_result f
INNER JOIN (
SELECT
id,
toyota,
mpg_toyota
FROM
pivot_result) t
ON
t.id = f.id
WHERE
(f.ford IS NOT NULL
AND f.mpg_ford IS NOT NULL
AND t.toyota IS NOT NULL
AND t.mpg_toyota IS NOT NULL)
GROUP BY
1,
2,
3,
4,
5
I have grouped sales from a sales view with sales below using
Select id, name, Count(*) as [Sales], product, amount
from vwSales
Group by
id,name, product, amount
ID | Name | Sales | Product | Amount
1 | Bob | 4 | Fridge | 40
1 | Bob | 12 | Washer | 120
2 | Anne | 5 | Fridge | 50
2 | Anne | 4 | Washer | 40
Is it possible to group these in to one row without using a join? So table looks something like
ID | Name | Fridge Sales | fridge Amt | Washer sales | washer amt
1 | Bob | 4 | 40 | 12 | 120
2 | Anne | 5 | 50 | 4 | 40
You can do conditional aggregation :
select id, name,
sum(case when Product = 'Fridge' then 1 else 0 end) as [Fridge Sales],
sum(case when Product = 'Fridge' then Amount else 0 end) as [fridge Amt],
sum(case when Product = 'Washer' then 1 else 0 end) as [Washer Sales],
sum(case when Product = 'Washer' then Amount else 0 end) as [Washer Amt]
from vwSales
Group by id, name;
I have a table like:
| client_id | product_type |
|-----------|--------------|
| c_1 | toy |
| c_2 | toy |
| c_3 | furniture |
| c_3 | furniture |
| c_3 | book |
| c_4 | toy |
| c_4 | furniture |
| c_5 | book |
| c_5 | book |
| c_5 | book |
As you can see, each client can have multiple products assigned.
I have to categorise each client by products they have.
If clients have product toy assigned to them, they should have toys
in the result table, no matter if they have other products.
If clients have product furniture assigned to them, they should have furnitures in the result table, no matter if they have other products.
If clients have product book assigned to them, they should have books in the result table, no matter if they have other products and so on...
Each client must appear in the results only once.
For the above example the result will be:
| client_id | cat |
|-----------|------------|
| c_1 | toys |
| c_2 | toys |
| c_3 | furnitures |
| c_4 | toys |
| c_5 | books |
You can use a CASE to assign the priority, e.g.
select client_id,
'cat_' +
min(case product_type
when 'toy' then '1'
when 'furniture' then '2'
when 'book' then '3'
end)
from tab
group by client_id
Would be easier if you have a table defining the category/priority for each product, then it's a simple join instead of CASE.
I think the logic to get the results you want is:
select client_id,
(case when sum(case when product_type = 'toy' then 1 else 0 end) > 0
then 'toys'
when sum(case when product_type = 'furniture' then 1 else 0 end) > 0
then 'furnitures'
when sum(case when product_type = 'book' then 1 else 0 end) > 0
then 'books'
end) as category
from t
group by client_id;
I have book stock table like :
---------------------------------------------------------------------
| BOOK_ID | WAREHOUSE | UNITS | QTY_IN | QTY_OUT |
---------------------------------------------------------------------
| 1 | W01 | PCS | 5 | 0 |
---------------------------------------------------------------------
| 2 | W02 | BOX | 1 | 0 |
---------------------------------------------------------------------
| 1 | W01 | PCS | 20 | 0 |
---------------------------------------------------------------------
| 1 | W01 | BOX | 2 | 0 |
---------------------------------------------------------------------
| 1 | W01 | PCS | 0 | 2 |
---------------------------------------------------------------------
I want to get final quantity for each book item, eg:
for BOOK_ID 1 TOTAL QTY IS 2 BOX, 23 PCS
for BOOK_ID 2 TOTAL QTY is 1 BOX
so on..
This is I had tried so far :
select BOOK_ID, UNITS, WAREHOUSE, sum(QTY_IN) as QTY_IN, sum(QTY_OUT) as QTY_OUT from
(select BOOK_ID, UNITS, WAREHOUSE, QTY_IN, QTY_OUT
from BOOK_STOCK) d
group by BOOK_ID, UNITS, WAREHOUSE
Please help me how to grouping and sum the quantity?
Thank you.
Use case expressions to do conditional aggregation:
select BOOK_ID,
sum(case when units = 'BOX' then QTY_IN - QTY_OUT else 0 end) as QTY_BOX,
sum(case when units = 'PCS' then QTY_IN - QTY_OUT else 0 end) as QTY_PCS
from BOOK_STOCK
group by BOOK_ID
Below code should do the trick for you.
select BOX.book_id, BOX.TotalQty as BoxFinalQuantity, PCS.TotalQty as PCSFinalQuantity
from
(
select book_id, units, sum(qty_in-qty_out) as TotalQty from #Books
where units like 'BOX'
group by book_id, units) BOX
full outer join (
select book_id, units, sum(qty_in-qty_out) as TotalQty from #Books
where units like 'PCS'
group by book_id, units) PCS ON BOX.book_id = Pcs.book_id