Return Count Value back as 0 if emtpy or none - oracle

I am running the following query in our database and I am trying to get the count value back as 0 if none are present, but having problems doing so. Could someone help assist and explain how to accomplish this
select state, count(phone_number) from VOIP_PHONE_NUMBER_POOL
where status = 3
group by state
order by state asc;
For example, currently my query is returning something back like this
State Count
AZ 25
When I want it to return the empty values and look like this
State Count
AZ 25
CA 0

This mimics what you have now:
SQL> with voip_phone_number_pool (state, phone_number, status) as
2 (select 'AZ', 1234, 3 from dual union all
3 select 'AZ', 2232, 3 from dual union all
4 select 'AZ', 4444, 3 from dual union all
5 select 'AZ', 7756, 1 from dual union all
6 --
7 select 'CA', 9999, 1 from dual
8 )
9 select state,
10 count(phone_number)
11 from voip_phone_number_pool
12 where status = 3
13 group by state
14 order by state;
ST COUNT(PHONE_NUMBER)
-- -------------------
AZ 3
SQL>
There's no row for the CA state which has status = 3, so it isn't returned by that query.
What you could do, is to use outer self-join in such a manner:
SQL> with voip_phone_number_pool (state, phone_number, status) as
2 (select 'AZ', 1234, 3 from dual union all
3 select 'AZ', 2232, 3 from dual union all
4 select 'AZ', 4444, 3 from dual union all
5 select 'AZ', 7756, 1 from dual union all
6 --
7 select 'CA', 9999, 1 from dual
8 ),
9 states as
10 (select distinct state from voip_phone_number_pool)
11 select s.state,
12 count(v.phone_number)
13 from states s left join voip_phone_number_pool v on v.state = s.state
14 and v.status = 3
15 group by s.state
16 order by s.state;
ST COUNT(V.PHONE_NUMBER)
-- ---------------------
AZ 3
CA 0
SQL>
the states CTE selects all states
it is then used in outer join with voip_phone_number_pool
note that condition (status = 3) has to be moved into join (line #14); if you leave it in the where clause, you won't get desired result

If there are no rows in the fact table (VOIP_PHONE_NUMBER_POOL) with a particular state, you will not get such a result from only querying that table.
You will need to join your fact table to a dimension table (a table with all possible states) in order to get the desired counts.
For example, assuming you have such a dimension table and it is named "state_info":
SELECT s.state,
COUNT(v.phone_number) AS phone_number_count
FROM state_info s
LEFT OUTER JOIN voip_phone_number_pool v
ON s.state = v.state
GROUP BY s.state;

SELECT s.state,
COUNT(v.phone_number) AS phone_number_count
FROM CORP_ACCT s
LEFT OUTER JOIN voip_phone_number_pool v
ON s.state = v.state
GROUP BY s.state;
worked for me

Related

I need 2 count columns in the same query in ORACLE

I'm trying to get the unique number of invoices a company has received and sent out using 2 count() functions. In invoices table there are two columns that are references to the same company id (one is id of a company that is sending an invoice and the other one is id of a company that is receiving an invoice)
This is the code I tried using:
SELECT K.ID,K.NAME,K.CITY, COUNT(*) AS NUM_OF_INVOICES_SENT, COUNT(*) AS NUM_OF_INVOICES_RECEIVED
FROM COMPANY K LEFT JOIN INVOICE F ON F.COMP_SNEDING = K.ID
GROUP BY K.NAME,K.ID,K.CITY
This is for a school project so I am in no means well versed in sql/oracle
actual data invoices:
actual data company:
desired outcome with given actual data:
Here's one option; it doesn't use count, but sum with case expression.
Sample data:
SQL> with
2 invoice (id, amount, comp_sending, comp_receiving) as
3 (select 1, 2000 , 1, 2 from dual union all
4 select 2, 28250, 3, 2 from dual union all
5 select 3, 8700 , 4, 1 from dual union all
6 select 4, 20200, 5, 3 from dual union all
7 select 5, 21500, 3, 4 from dual
8 ),
9 company (id, name, city, state) as
10 (select 1, 'Microsoft', 'Redmond' , 'Washington' from dual union all
11 select 2, 'Ubisoft' , 'Paris' , 'France' from dual union all
12 select 4, 'Starbucks', 'Seattle' , 'Washington' from dual union all
13 select 5, 'Apple' , 'Cupertino', 'California' from dual union all
14 select 3, 'Nvidia' , 'Cupertino', 'California' from dual
15 )
Query begins here:
16 select c.id, c.name,
17 sum(case when c.id = i.comp_sending then 1 else 0 end) cnt_sent,
18 sum(case when c.id = i.comp_receiving then 1 else 0 end) cnt_received
19 from company c left join invoice i on c.id in (i.comp_sending, i.comp_receiving)
20 group by c.id, c.name
21 order by c.id;
ID NAME CNT_SENT CNT_RECEIVED
---------- --------- ---------- ------------
1 Microsoft 1 1
2 Ubisoft 0 2
3 Nvidia 2 1
4 Starbucks 1 1
5 Apple 1 0
SQL>
You can use COUNT if you replace the 0 in the CASE expressions with NULL. So #Littlefoot's query becomes
select c.id, c.name,
COUNT(case when c.id = i.comp_sending then 1 else NULL end) cnt_sent,
COUNT(case when c.id = i.comp_receiving then 1 else NULL end) cnt_received
from company c left join invoice i on c.id in (i.comp_sending, i.comp_receiving)
group by c.id, c.name
order by c.id;
This works because COUNT counts only those rows which have a non-NULL value in the expression which is being counted.
db<>fiddle here

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>

join in oracle using in clause for a list [duplicate]

This question already has answers here:
How to split a varchar column as multiple values in SQL?
(2 answers)
What is alternative of Find_in_set of mysql in Oracle
(3 answers)
Oracle joining tables using WITH clause with SPLIT [duplicate]
(2 answers)
use LIKE and IN with subquery in sql [duplicate]
(4 answers)
Closed 1 year ago.
I am having 2 tables, 1 is transaction, other is trackingNumber
Transaction have trackingNumberList which contains the values like 123, 235, 55. Here 123 is the id of trackingNumber, same for other 2 values.
I wanna join transaction with trackingNumber but I haven't found any solution to join list.
I tried INSTR as well but it is not giving the correct data.
select tn.*, t.id
from transaction t
left join TrackingNumber tn on INSTR(t.trackingnumberlist, tn.id) > 0
where t.id = 2439845;
I am using ORACLE db.
Don't split the string; just wrap the list and the id in the delimiter you are using and do a sub-string match using LIKE:
select tn.*, t.id
from transaction t
left join TrackingNumber tn
on (', '||t.trackingnumberlist||', ' LIKE '%, '||tn.id||', %')
where t.id = 2439845;
If you want to use INSTR to do the same thing:
select tn.*, t.id
from transaction t
left join TrackingNumber tn
on (INSTR(', '||t.trackingnumberlist||', ', ', '||tn.id||', ') > 0)
where t.id = 2439845;
If you split comma-separated values into rows, then you can join such a subquery with another table. Have a look at the following example. Sample data in lines #1 - 11, query you might be interested in begins at line #12.
SQL> with
2 transaction (trackingnumberlist, city) as
3 (select '123, 235, 55', 'London' from dual union all
4 select '22' , 'Paris' from dual
5 ),
6 trackingnumber (id, name) as
7 (select '123', 'Little' from dual union all
8 select '235', 'Foot' from dual union all
9 select '55' , 'Sharma' from dual union all
10 select '22' , 'Barmar' from dual
11 )
12 select n.id,
13 n.name,
14 x.city
15 from trackingnumber n
16 join (select trim(regexp_substr(t.trackingnumberlist, '[^,]+', 1, column_value)) id,
17 t.city
18 from transaction t cross join
19 table(cast(multiset(select level from dual
20 connect by level <= regexp_count(t.trackingnumberlist, ',') + 1
21 ) as sys.odcinumberlist ))
22 ) x
23 on x.id = n.id
24 order by n.id, n.name;
ID NAME CITY
--- ------ ------
123 Little London
22 Barmar Paris
235 Foot London
55 Sharma London
SQL>

How to breakdown data by month and showing zero for months with no data?

Using information in Table A, how can I produce results in Table B below?
Table A:
CASE_ID DATE_EFF COPAY STATUS
1 11/04/2016 10 A
1 11/20/2016 5 A
1 11/23/2016 5 R
1 12/01/2016 1 A
1 12/10/2016 2 A
1 12/12/2016 10 A
1 12/31/2016 50 R
For the above CASE_ID, we have dates in Nov 2016 and Dec 2016 only, however, I want to produce a breakdown of this CASE_ID for a period of 6 months as below where for each month the copays are summed where applicable as per the DATE_EFF and for the months that are not within the above dates, a zero is entered. Also, only records with copays with a status of 'A' are summed for any month -- so those with status of 'R' are ignored in the summation. For example, based on data in Table A above, the intended results are as follow:
Table B:
CASE_ID MONTH TOTAL_COPAY
1 01/2017 0
1 12/2016 13
1 11/2016 15
1 10/2016 0
1 09/2016 0
1 08/2016 0
I have below as a possible solution[using a with clause], but can this be achieved without the use of the 'with' clause?
Possible Solution:
WITH
XRF AS
( SELECT CASE_ID, COPAY, DATE_EFF
FROM Table_A WHERE STATUS = 'A'
)
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM XRF F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;
UPDATE AND SOLUTION:
Using the above query, I believe I am have answered my own question by implementing it as below -- not sure though if using this method is expensive when you have millions of records of such CASE_IDs. Any thoughts?
SELECT F.CASE_ID, ST, NVL(SUM(F.COPAY),0) TOTAL_COPAY FROM (SELECT CASE_ID, COPAY, DATE_EFF FROM TABLE_A WHERE STATUS = 'A') F PARTITION BY (F.CASE_ID)
RIGHT OUTER JOIN (SELECT '12/2016' ST FROM DUAL UNION ALL
SELECT '11/2016' FROM DUAL UNION ALL
SELECT '10/2016' FROM DUAL UNION ALL
SELECT '09/2016' FROM DUAL UNION ALL
SELECT '08/2016' FROM DUAL UNION ALL
SELECT '07/2016' FROM DUAL) STS
ON (TO_CHAR(LAST_DAY((F.DATE_EFF)),'MM/YYYY') = STS.ST)
GROUP BY F.CASE_ID, ST ORDER BY F.CASE_ID, ST DESC
;

scalar subquery has an aggregate operation

My oracle version is 10.2.
It's very strange when a scalar subquery has an aggregate operation.
my table named t_test looked like this;
t_id t_name
1 1
2 1
3 2
4 2
5 3
6 3
query string looked like this;
select t1.t_id,
(select count(t_name)
from (select t2.t_name
from t_test t2
where t2.t_id=t1.t_id
group by t2.t_name)) a
from t_test t1
this query's result is,
t_id a
1 3
2 3
3 3
4 3
5 3
6 3
which is very weird,
take t1.t_id=1 for example,
select count(t_name)
from (select t2.t_name
from t_test t2
where t2.t_id=1
group by t2.t_name)
the result is 1,
somehow,the 'where' operator doesn't work,the result is exactly the same as I put my query like this:
select t1.t_id,
(select count(t_name)
from (select t2.t_name
from t_test t2
group by t2.t_name)) a
from t_test t1
why?
Can you post a cut-and-paste from SQL*Plus showing exactly what query you're running? The query you posted does not appear to be valid-- the alias t1 is not going to be valid in the subquery where you're referencing it. That makes me suspect that you're simplifying the problem to post here but you've accidentally left something important out.
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select 1 id, 1 name from dual union all
3 select 2,1 from dual union all
4 select 3,2 from dual union all
5 select 4,2 from dual union all
6 select 5,3 from dual union all
7 select 6,3 from dual
8 )
9 select t1.id
10 ,(select count(b.name)
11 from (select t2.name
12 from x t2
13 where t2.id = t1.id
14 group by t2.name) b) a
15* from x t1
SQL> /
where t2.id = t1.id
*
ERROR at line 13:
ORA-00904: "T1"."ID": invalid identifier
Presumably, it would be much more natural to write the query like this (assuming you really want to use a scalar subquery) where t1 is going to be a valid alias in the scalar subquery.
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select 1 id, 1 name from dual union all
3 select 2,1 from dual union all
4 select 3,2 from dual union all
5 select 4,2 from dual union all
6 select 5,3 from dual union all
7 select 6,3 from dual
8 )
9 select t1.id
10 ,(select count(t2.name)
11 from x t2
12 where t2.id = t1.id) cnt
13* from x t1
SQL> /
ID CNT
---------- ----------
1 1
2 1
3 1
4 1
5 1
6 1
6 rows selected.

Resources