How to sum total amount without grouping even have duplicated number? - oracle

table_a table_b
desc amount ID vcref ID
banana 2.00 101 VC10001 101
apple 3.00 101 VC10001 101
orange 5.00 101 VC10003 101
select sum(a.amount),b.vcref from table_a a,table_b b where a.ID=b.ID group by b.vcref;
result
20.0 VC10001
10.0 VC10003
-------------------------------------------
May I know it is possible to show result like this ?
result
10.0 VC10001
10.0 VC10001
10.0 VC10003
Anyone help is much appreciated.

One option is to use a correlated subquery:
Sample data:
SQL> with
2 table_a (c_desc, amount, id) as
3 (select 'banana', 2, 101 from dual union all
4 select 'apple' , 3, 101 from dual union all
5 select 'orange', 5, 101 from dual
6 ),
7 table_b (vcref, id) as
8 (select 'vc1001', 101 from dual union all
9 select 'vc1001', 101 from dual union all
10 select 'vc1003', 101 from dual
11 )
Query:
12 select b.vcref,
13 (select sum(a.amount) from table_a a where a.id = b.id) total
14 from table_b b;
VCREF TOTAL
------ ----------
vc1001 10
vc1001 10
vc1003 10
SQL>

Select the sum as an inner query:
select
(select sum(amount) from table_a) as result,
vcref
from table_b

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 query to keep looking until value is not 0 anymore

I am using Oracle 11.
I have 2 tables
TblA with columns id, entity_id and effective_date.
TblADetail with columns id and value.
If Value = 0 for the effective date, I want to keep looking for the next effective date until I found value <> 0 anymore.
The below query only look for value on 3/10/21.
If value = 0, I want to look for value on 3/11/21. If that's not 0, I want to stop.
But, if that's 0, I want to look for value on 3/12/21. If that's not 0, I want to stop.
But, if that's 0, I want to keep looking until value is not 0.
How can I do that ?
SELECT SUM(pd.VALUE)
FROM TblA p,TblADetail pd
WHERE p.id = pd.id
AND p.effective_date = to_date('03/10/2021','MM/DD/YYYY')
AND TRIM (p.entity_id) = 123
Sample data:
TblA
id entity_id effective_date
1 123 3/10/21
2 123 3/11/21
3 123 3/12/21
TblADetail
id value
1 -136
1 136
2 2000
3 3000
In the above data, for entity_id 123, starting from effective_date 3/10/21, I would like to to return value 2000 (from TblADetail) effective_date 3/11/21.
So, starting from a certain date, I want the results from the minimum date that has non-zero values.
Thank you.
You can do what you need to do by grouping the sum on the effective date, and using the MIN analytic function to find the earliest date. Once you've done that, you simply need to select the date that matches the earliest date.
E.g.:
with tbla as (select 1 id, ' 123' entity_id, to_date('10/03/2021', 'dd/mm/yyyy') effective_date from dual union all
select 2 id, ' 123' entity_id, to_date('11/03/2021', 'dd/mm/yyyy') effective_date from dual union all
select 3 id, ' 123' entity_id, to_date('12/03/2021', 'dd/mm/yyyy') effective_date from dual),
tbla_detail as (select 1 id, -136 value from dual union all
select 1 id, 136 value from dual union all
select 2 id, 2000 value from dual union all
select 3 id, 3000 value from dual),
results as (select a.effective_date,
sum(ad.value) sum_value,
min(case when sum(ad.value) != 0 then a.effective_date end) over () min_effective_date
from tbla a
inner join tbla_detail ad on a.id = ad.id
where a.effective_date >= to_date('10/03/2021', 'dd/mm/yyyy')
and trim(a.entity_id) = '123'
group by a.effective_date)
select sum_value
from results
where effective_date = min_effective_date;
SUM_VALUE
----------
2000
Straightforward; read comments within code. Sample data in lines #1 - 13, query begins at line #14.
SQL> with
2 -- sample data
3 tbla (id, entity_id, effective_date) as
4 (select 1, 123, date '2021-03-10' from dual union all
5 select 2, 123, date '2021-03-11' from dual union all
6 select 3, 123, date '2021-03-12' from dual
7 ),
8 tblb (id, value) as
9 (select 1, -136 from dual union all
10 select 1, 136 from dual union all
11 select 2, 2000 from dual union all
12 select 3, 3000 from dual
13 ),
14 tblb_temp as
15 -- simple grouping per ID
16 (select id, sum(value) value
17 from tblb
18 group by id
19 )
20 -- return TBLA values whose ID equals TBLB_TEMP's minimum ID
21 -- whose value isn't zero
22 select a.id, a.entity_id, a.effective_date
23 from tbla a
24 where a.id = (select min(b.id)
25 from tblb_temp b
26 where b.value > 0
27 );
ID ENTITY_ID EFFECTIVE_
---------- ---------- ----------
2 123 03/11/2021
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;

how to write query to display two rows in one row from same table with different alias column names using oracle

i need to display two rows from same table with different column names. one as Current columns and other as previous columns. How to display it in one row.
SELECT BILL_ID CUR_BILL_ID, BILL_START_DT CUR_BILL_START_DT, BILL_END_DT CUR_BILL_END_DT, BILL_STATUS_CD CUR_BILL_STATUS_CD, BILL_APPROVED_BY CUR_BILL_APPROVED_BY, BILL_APPROVED_DT CUR_BILL_APPROVED_DT FROM FPM_CB_BILL_DETAILS WHERE BILL_ID = (select max(BILL_ID) from FPM_CB_BILL_DETAILS)
SELECT BILL_ID PRV_BILL_ID, BILL_START_DT PRV_BILL_START_DT, BILL_END_DT PRV_BILL_END_DT, BILL_STATUS_CD PRV_BILL_STATUS_CD, BILL_APPROVED_BY PRV_BILL_APPROVED_BY, BILL_APPROVED_DT PRV_BILL_APPROVED_DT FROM FPM_CB_BILL_DETAILS WHERE BILL_ID = (select max(BILL_ID) from FPM_CB_BILL_DETAILS) - 1
Looks like selfjoin might help.
SQL> with fpm_cb_bill_Details (bill_id, bill_status_cd) as
2 (select 100, 'status A' from dual union all
3 select 101, 'status B' from dual union all
4 select 102, 'statuc C' from dual union all
5 select 103, 'status D' from dual
6 )
7 select a.bill_id curr_bill_id,
8 a.bill_status_cd curr_status,
9 b.bill_id prev_bill_id,
10 b.bill_status_cd prev_status
11 from fpm_cb_bill_details a join fpm_cb_bill_details b on b.bill_id = a.bill_id - 1
12 where a.bill_id = (select max(bill_id) from fpm_cb_bill_details);
CURR_BILL_ID CURR_STA PREV_BILL_ID PREV_STA
------------ -------- ------------ --------
103 status D 102 statuc C
SQL>
You can use lag() analytic function to see the previous row's column values, ordering by bill_id as follows:
FSITJA#db01> with fpm_cb_bill_Details (bill_id, bill_status_cd) as
2 (select 100, 'status A' from dual union all
3 select 101, 'status B' from dual union all
4 select 102, 'statuc C' from dual union all
5 select 103, 'status D' from dual
6 )
7 select d.bill_id curr_bill_id,
8 d.bill_status_cd curr_status,
9 lag(d.bill_id) over (order by d.bill_id) prev_bill_id,
10 lag(d.bill_status_cd) over (order by d.bill_id) prev_status
11 from fpm_cb_bill_Details d;
CURR_BILL_ID CURR_STA PREV_BILL_ID PREV_STA
------------ -------- ------------ --------
100 status A
101 status B 100 status A
102 statuc C 101 status B
103 status D 102 statuc C
Thanks #Littlefoot for the sample table data.

oracle- JOIN 2 tables with 2 ID's in common

table "team1" :
id country
1 India
2 Pakistan
3 srilanka
4 England
table "team2" :
id name name2
1 2 4
2 1 3
i have to combine two tables
another table when retrieve the data that time in place of 2 , 4 Pakistan,England
It is about the self join of team1 table (lines #15 and 16):
SQL> with
2 team1 (id, country) as
3 (select 1, 'India' from dual union all
4 select 2, 'Pakistan' from dual union all
5 select 3, 'Sri Lanka' from dual union all
6 select 4, 'England' from dual
7 ),
8 team2 (id, name, name2) as
9 (select 1, 2, 4 from dual union all
10 select 2, 1, 3 from dual
11 )
12 select b.id,
13 t1.country,
14 t2.country
15 from team2 b join team1 t1 on t1.id = b.name
16 join team1 t2 on t2.id = b.name2
17 order by b.id;
ID COUNTRY COUNTRY
---------- --------- ---------
1 Pakistan England
2 India Sri Lanka
SQL>
Just showing another way of writing the same query with aggregate functions and grouping.
with
team1 (id, country) as
(select 1, 'India' from dual union all
select 2, 'Pakistan' from dual union all
select 3, 'Sri Lanka' from dual union all
select 4, 'England' from dual
),
team2 (id, name, name2) as
(select 1, 2, 4 from dual union all
select 2, 1, 3 from dual
)
SELECT
T2.ID,
MAX(CASE
WHEN T2.NAME = T1.ID THEN T1.COUNTRY
END) AS TEAM1,
MAX(CASE
WHEN T2.NAME2 = T1.ID THEN T1.COUNTRY
END) AS TEAM2
FROM
TEAM2 T2
JOIN TEAM1 T1 ON T1.ID IN (
T2.NAME,
T2.NAME2
)
GROUP BY
T2.ID
ORDER BY
T2.ID;
Output:
ID TEAM1 TEAM2
---------- --------- ---------
1 Pakistan England
2 India Sri Lanka
Cheers!!

Resources