Oracle PIVOT a select statement - oracle

I would like to pivot a select statement.
Columns "Country", "Store" and "Sales" are given.
Now I would like to have an output like:
Store1 Store2 Store3
Country1 2342 2342 5675
Country2 5753 3274 7326
Country3 1543 4367 3367
So basically I need the salescount for every Store, for every Country.
The Input comes from (example):
Country: StoreNr: ProductSold:
Belgium 23 Car
Belgium 23 House
Netherland 23 Car
Output would be:
Store23
Belgium 2
Netherlands 1

If the number of stores is finite, you could use one of these approaches:
Using count() aggregate function combined with case expression:
-- sample of data. just for the sake of demonstration
SQL> with t1(Country, StoreNr, ProductSold) as(
2 select 'Belgium' , 23, 'Car' from dual union all
3 select 'Belgium' , 23, 'House' from dual union all
4 select 'Netherland', 23, 'Car' from dual union all
5 select 'Belgium' , 25, 'House' from dual
6 )
7 select country
8 , count(case
9 when StoreNr = 23
10 then 1
11 end) as storeNr_23
12 , count(case
13 when StoreNr = 25
14 then 1
15 end) as storeNr_25
16 from t1
17 group by country
18 ;
Result:
COUNTRY STORENR_23 STORENR_25
---------- ---------- ----------
Belgium 2 1
Netherland 1 0
Starting from Oracle 11g and up, the pivot operator as follows:
select *
from (Select country as country
, country as country_cnt
, StoreNr
from t1)
pivot( -- list all store numbers here
count(country_cnt) for storenr in ( 23 as StoreNr_23
, 25 as StoreNr_25)
)
Result:
COUNTRY STORENR_23 STORENR_25
---------- ---------- ----------
Belgium 2 1
Netherland 1 0

Related

single result for 2 queries ORACLE

I have a POST table, a CATEGORY table, a ACTION table and ACTION_TYPE table, I explain the ACTION table contains all the actions that were made, and the table ACTION_TYPE contains the actions details for example the ACTION whose ID = 4 has ACTION_TYPE_ID = 1 for POST_ID 6, which mean an action was made for post number 50, we can have many actions for one post_id
The POST table
id title content category_id
---------- ---------- ---------- ------------
1 title1 Text... 1
2 title2 Text... 1
3 title3 Text... 1
4 title4 Text... 3
5 title5 Text... 2
6 title6 Text... 1
The CATEGORY table
id name
---------- ----------
1 category_1
2 category_2
3 category_3
The ACTION_TYPE table
id name
---------- ----------
1 updated
2 deleted
3 restored
4 hided
The ACTION table
id post_id action_type_id date
---------- ---------- -------------- -----
1 1 1 2017-01-01
2 1 1 2017-02-15
3 1 3 2018-06-10
4 6 1 2019-08-01
5 5 2 2019-12-09
6 2 3 2020-04-27
7 2 1 2020-07-29
8 3 2 2021-03-13
Now I explain the case, I actually have two queries a query to count the posts for each category and another to count the actions performed on each post by category which work perfectly.
Here is my first query
select categories, count(*) as cnt_posts_per_cat
from(
select
case
when p.category_id is not null then c.name
end as categories
from post p
left join category c on p.category _id = c.id
)
group by categories
;
Which brings this result
categories cnt_posts_per_cat
---------- -------------------
category_1 4
category_2 1
category_3 1
Ans here is my second query
select categories, count(*) as cnt_actions_per_cat
from(
select distinct ac.post_id AS action_post_id, max(ac.date) over (partition by ac.post_id) as max_date,
case
when ac.action_type_id is not null then act.name
end as actions,
case
when p.category_id is not null then c.name
else 'na'
end as categories
from action ac
left join post p on ac.post_id = p.id
left join category c on p.category _id = c.id
left join action_type act on ac.action_type_id = act.id
where act.name in ('restored','deleted','updated')
)
group by categories
;
Which brings this correct result because it's seclect the last action for each action_type
categories cnt_actions_per_cat
---------- -------------------
category_1 3
category_2 1
category_3 na
But I would like to have a single result table for both queries at the same time as follow :
Here the result expected to be
categories cnt_posts_per_cat cnt_actions_per_cat
---------- ----------------- -------------------
category_1 4 3
category_2 1 1
category_3 1 na
i was trying union and union all but it's not correct it return following result
categories cnt_posts_per_cat
---------- -----------------
category_1 7
category_2 2
category_3 1
Best regards
How about correlated subqueries?
Sample data:
SQL> with
2 post (id, category_id) as
3 (select 1, 1 from dual union all
4 select 2, 1 from dual union all
5 select 3, 1 from dual union all
6 select 4, 3 from dual union all
7 select 5, 2 from dual union all
8 select 6, 1 from dual
9 ),
10 category (id, name) as
11 (select 1, 'category_1' from dual union all
12 select 2, 'category_2' from dual union all
13 select 3, 'category_3' from dual
14 ),
15 action_type (id, name) as
16 (select 1, 'updated' from dual union all
17 select 2, 'deleted' from dual union all
18 select 3, 'restored' from dual union all
19 select 4, 'hided' from dual
20 ),
21 action (id, post_id, action_type_id) as
22 (select 1, 1, 1 from dual union all
23 select 2, 1, 1 from dual union all
24 select 3, 1, 3 from dual union all
25 select 4, 6, 1 from dual union all
26 select 5, 5, 2 from dual union all
27 select 6, 2, 3 from dual union all
28 select 7, 2, 1 from dual union all
29 select 8, 3, 2 from dual
30 )
Query begins here:
31 select c.name,
32 --
33 (select count(*)
34 from post p
35 where p.category_id = c.id
36 ) cnt_posts_per_cat,
37 --
38 (select count(*)
39 from action a join post p on p.id = a.post_id
40 join action_type t on t.id = a.id
41 where p.category_id = c.id
42 and t.name in ('restored', 'deleted', 'updated')
43 ) cnt_actions_per_cat
44 from category c
45 order by c.name;
NAME CNT_POSTS_PER_CAT CNT_ACTIONS_PER_CAT
---------- ----------------- -------------------
category_1 4 3
category_2 1 0
category_3 1 0
SQL>

Oracle Subquery while using count and max with join

Table COMPUTER:
Table SUPPLIER:
how to display the building location that has the most computers?
i Have been trying several ways include subquery, joins, max, count but all not working and error keeps happending
The result i pursueing is
SUPPID SNAME SADDRESS MAKE COUNT(*)
125 Apple Sdn.Bhd 18 Jalan Duta Apple 3
For example (where sample data is in lines #1 - 12; query you might be interested in begins at line #13):
SQL> with
2 -- sample data
3 computer (compid, make, suppid, locid) as
4 (select 13323, 'IBM' , 124, 333 from dual union all
5 select 13324, 'Apple', 125, 444 from dual union all
6 select 13325, 'Apple', 125, 444 from dual union all
7 select 13326, 'Apple', 125, 444 from dual
8 ),
9 supplier (suppid, sname, saddress) as
10 (select 124, 'IBM Sdn.Bhd' , '15 Jalan Duta' from dual union all
11 select 125, 'Apple Sdn.Bhd', '18 Jalan Duta' from dual
12 ),
13 comp_loc as
14 -- number of computers per location; RNK = 1 shows location with most computers
15 (select locid,
16 rank() over (order by count(*) desc) rnk,
17 count(*) cnt
18 from computer
19 group by locid
20 )
21 select distinct s.suppid, s.sname, s.saddress, c.make, l.cnt
22 from supplier s join computer c on c.suppid = s.suppid
23 join comp_loc l on l.locid = c.locid
24 where l.rnk = 1;
SUPPID SNAME SADDRESS MAKE CNT
---------- ------------- ------------- ----- ----------
125 Apple Sdn.Bhd 18 Jalan Duta Apple 3
SQL>
On Oracle 12 and newer
select s.suppid, s.sname, s.saddress, c.make, count(1)
from COMPUTER c
join SUPPLIER s
on c.suppid = s.suppid
group by s.suppid, s.sname, s.saddress, c.make
order by count(1) desc
fetch first 1 row only <-- this line will fetch you the top 1 line only
You might also use "fetch first 1 row with ties" to output all the top manufacturers if there are many of them having same "count". E.g If IBM and Appl were having same amount of lines
On Oracle version before 12 do the following:
select *
from (select s.suppid, s.sname, s.saddress, c.make, count(1)
from comps c
join suppls s
on c.suppid = s.suppid
group by s.suppid, s.sname, s.saddress, c.make
order by count(1) desc)
where rownum = 1; <-- this line will get you the top 1 manufacturer only
PS. version of the oracle database can be obtained for example using:
select version from v$instance;

Create a product base table by date

I want to create a query that returns number of active products by colander date. I don’t have calendar dim table in database.
Current table
Product_name|prod_id|start_date|end_date
P1|1234|02/01/2020|30/05/2020
P1|2345|02/01/2020|31/12/9999
P1|3456|03/01/2020|31/12/9999
Expected Result
Calander_date|product_name|active_base
01/01/2020|P1|0
02/01/2020|P1|2
03/01/2020|P1|3
01/06/2020|P1|2
Create your own calendar, then - either in the database, as a "real" table (row generator technique helps here), or as a CTE (as I did in the following example):
SQL> with
2 test (product_name, prod_id, start_date, end_date) as
3 -- you have that table; don't type that
4 (select 'P1', 1234, date '2020-01-02', date '2020-05-30' from dual union all
5 select 'P1', 2345, date '2020-01-02', date '9999-12-31' from dual union all
6 select 'P1', 3456, date '2020-01-03', date '9999-12-31' from dual
7 ),
8 calendar (datum) as
9 -- create your own calendar table
10 (select date '2020-01-01' + level - 1
11 from dual
12 connect by level <= 10000 --> number of days you want in calendar
13 )
14 -- final query - join!
15 select c.datum,
16 t.product_name,
17 count(*) active_base
18 from calendar c join test t on c.datum between t.start_date and t.end_date
19 group by c.datum, t.product_name
20 order by c.datum;
DATUM PR ACTIVE_BASE
---------- -- -----------
02/01/2020 P1 2
03/01/2020 P1 3
04/01/2020 P1 3
05/01/2020 P1 3
06/01/2020 P1 3
<snip>
28/05/2020 P1 3
29/05/2020 P1 3
30/05/2020 P1 3
31/05/2020 P1 2
01/06/2020 P1 2
02/06/2020 P1 2
<snip>

ORACLE HOW TO GET DATA IN THIS FORMAT

I have a table structure like this in Oracle
Product_ID Product_SKU Product_Zone Product_Price
1 123 Zone1 10
2 123 Zone2 12
3 456 Zone1 13
4 456 Zone2 14
How I can get the result in horizontal format like this
Product_SKU Zone1_Price Zone2_Price
123 10 12
456 13 14
Thanks
Here's a simple, aggregation option:
SQL> with test (product_id, product_sku, product_zone, product_price) as
2 -- sample data
3 (select 1, 123, 'zone1', 10 from dual union all
4 select 2, 123, 'zone2', 12 from dual union all
5 select 3, 456, 'zone1', 13 from dual union all
6 select 4, 456, 'zone2', 14 from dual
7 )
8 select product_sku,
9 max(case when product_zone = 'zone1' then product_price end) zone1_price,
10 max(case when product_zone = 'zone2' then product_price end) zone2_price
11 from test
12 group by product_sku;
PRODUCT_SKU ZONE1_PRICE ZONE2_PRICE
----------- ----------- -----------
123 10 12
456 13 14
SQL>

How to select data from a single column in Oracle and display results in multiple columns?

my table;
Date | Cost
01.01.2010 | 100
02.01.2010 | 200
03.01.2010 | 300
04.01.2010 | 400
10.01.2010 | 800
11.01.2010 | 800
12.01.2010 | 800
25.01.2010 | 500
26.01.2010 | 500
05.02.2010 | 600
13.02.2010 | 700
15.02.2010 | 700
ı want to make "date between '01.01.2010' and '28.02.2010' " weekly view
Week 1 | Week 2 | week 3 | week . .. .
1000 | 2400 | 0 | 32432.... . .
How to make pls help thank you ?
SQL> create table mytable (the_date,cost)
2 as
3 select date '2010-01-01', 100 from dual union all
4 select date '2010-01-02', 200 from dual union all
5 select date '2010-01-03', 300 from dual union all
6 select date '2010-01-04', 400 from dual union all
7 select date '2010-01-10', 800 from dual union all
8 select date '2010-01-11', 800 from dual union all
9 select date '2010-01-12', 800 from dual union all
10 select date '2010-01-25', 500 from dual union all
11 select date '2010-01-26', 500 from dual union all
12 select date '2010-02-05', 600 from dual union all
13 select date '2010-02-13', 700 from dual union all
14 select date '2010-02-15', 700 from dual
15 /
Table created.
This query uses MAX-DECODE as a standard pivot technique. If you are on version 11, you can also use the PIVOT operator. The below version will work on any version.
SQL> select nvl(max(decode(the_week,'01',cost)),0) "Week 1"
2 , nvl(max(decode(the_week,'02',cost)),0) "Week 2"
3 , nvl(max(decode(the_week,'03',cost)),0) "Week 3"
4 , nvl(max(decode(the_week,'04',cost)),0) "Week 4"
5 , nvl(max(decode(the_week,'05',cost)),0) "Week 5"
6 , nvl(max(decode(the_week,'06',cost)),0) "Week 6"
7 , nvl(max(decode(the_week,'07',cost)),0) "Week 7"
8 , nvl(max(decode(the_week,'08',cost)),0) "Week 8"
9 , nvl(max(decode(the_week,'09',cost)),0) "Week 9"
10 from ( select to_char(the_date,'ww') the_week
11 , sum(cost) cost
12 from mytable
13 where the_date between date '2010-01-01' and date '2010-02-28'
14 group by to_char(the_date,'ww')
15 )
16 /
Week 1 Week 2 Week 3 Week 4 Week 5 Week 6 Week 7 Week 8 Week 9
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1000 2400 0 1000 0 600 1400 0 0
1 row selected.
Regards,
Rob.
select to_char(date, 'ww'), sum(cost)
from table
group by to_char(date, 'ww');
Or something along those lines should bring sums by week with the week number in the result. Link to Oracle 11g to_char syntax and link to format values. If that doesn't do it and you don't need the week number trunc(date, 'DAY') might be what you're looking for.
Not elegant solution, but its works...
SELECT SUM(Week1) Week1, SUM(Week2) Week2 ... SUM(Week36) Week36,
SUM(Week36) Week37
FROM (SELECT DECODE(WeekNo, 1, Cost, 0) Week1,
DECODE(WeekNo, 2, Cost, 0) Week2,
...
DECODE(WeekNo, 36, Cost, 0) Week36,
DECODE(WeekNo, 37, Cost, 0) Week37
FROM (SELECT to_char(DateFrom, 'IW') WeekNo, SUM(cost) Cost
FROM (SELECT trunc(SYSDATE) + LEVEL - 1 DateFrom,
LEVEL * 100 Cost
FROM dual
CONNECT BY LEVEL < 40)
GROUP BY to_char(DateFrom, 'IW')))

Resources