Oracle conditional WHERE in stored procedure

Viewed 181

I want to write a stored procedure to select carriers, with an additional parameter 'i_showEmptyCarrier' to specify if empty carriers needs to be hidden or showed.

+---------------------------+
|          Carriers         |
+----+----------+-----------+
| id | label    | location  |
+----+----------+-----------+
| 1  | carrier1 | warehouse |
+----+----------+-----------+
| 2  | carrier2 | warehouse |
+----+----------+-----------+
| 3  | carrier3 | factory   |
+----+----------+-----------+

I need to query the 'products' table to check if the carrier is empty or not.

+-------------------------------------------+
|                  products                 |
+----+-----------+----------------+---------+
| id | carrierid | productiondate | deleted |
+----+-----------+----------------+---------+
| 1  | 1         | 09/09/2020     | 1       |
+----+-----------+----------------+---------+
| 2  | 1         | 09/09/2020     | 0       |
+----+-----------+----------------+---------+
| 3  | 1         | 09/09/2020     | 0       |
+----+-----------+----------------+---------+
| 4  | 2         | 10/09/2020     | 0       |
+----+-----------+----------------+---------+
| 5  | 2         | 10/09/2020     | 0       |
+----+-----------+----------------+---------+

So in this case carrier3 is empty.
The stored procedure logic I want to have is:

PROCEDURE GetCarriers
(
    i_showEmptyCarrier IN number,
    c_Carriers OUT t_cursor
)
AS
BEGIN
OPEN c_Carriers FOR 
SELECT 
label,
(   select count(*) 
    from products 
    where products.carrierid = carriers.carrierid
    and records.deleted = 0
) as nrOfProducts
FROM carriers
if(i_showEmptyCarrier == 1) {
//select carriers without a product
WHERE nrOfProducts = 0 ;
}
else{
//select carriers with a product
WHERE nrOfProducts > 0 ;
}
END GetCarriers;

so if 'i_showEmptyCarrier' = 1, then empty carrier no.3 will be selected,

+----------+--------------+
| label    | nrOfProducts |
+----------+--------------+
| carrier3 | 0            |
+----------+--------------+

otherwise only carrier no.1 and 2 are selected.

+----------+--------------+
| label    | nrOfProducts |
+----------+--------------+
| carrier1 | 2            |
+----------+--------------+
| carrier2 | 2            |
+----------+--------------+
3 Answers

How about modifying the query to use left join and conditional aggregation and finally comparing the input,

SELECT label,nrOfProducts
FROM
(
  SELECT c.label,SUM(CASE WHEN p.deleted = 0 THEN 1 ELSE 0 END) nrOfProducts
   FROM carriers c
  LEFT JOIN products p 
  ON p.carrierid = c.id
  GROUP BY c.label
)
WHERE ((&i_showEmptyCarrier = 1 AND nrOfProducts = 0) 
       OR (&i_showEmptyCarrier = 0 AND nrOfProducts > 0));

You can still use the where clause for your query instead of if-else.

You want an inner join in one case and an outer join in the other. As an outer join just means that all columns of the outer-joined row are null, however, you can simply outer join in both cases and only then decide whether to dismiss or keep the outer-joined rows.

In SQL this is simply:

select *
from carriers c
left join products p on p.carrierid = c.id
where (:show_empty = 'only non-empty' and p.id is not null)
   or (:show_empty = 'only empty' and p.id is null)
   or (:show_empty = 'all')

(And of course you can aggregate this to count(p.id). In that case you can either group by c.id or look at one carrier where c.id = :carrier_id.)

Seems like you have a lot of Java (or other programming language) influence. I am not sure what exactly you want. But here is how you can achieve what you want.

create or replace procedure p_get_carriers(pi_carrier_flag in varchar2, po_carriers out t_cursor)
is
    lt_cursor   t_cursor;
begin
    select  *
    bulk collect into lt_cursor
    from    records
    where   deleted = case when pi_carrier_flag = 'Y' then 0 else deleted end;
    po_carriers := lt_cursor;
exception
when others then
    po_carriers := null;
end p_get_carriers;

Meaning you don't need to have if-else block to handle that. You can do it in the where clause of the query itself.

Note: I am not aware of your table structure and the collection details. I am guessing it and posting the code. You might need to adjust it accordingly.

Related