Oracle 条件存储过程中的 WHERE
Oracle conditional WHERE in stored procedure
我想为 select 载体编写一个存储过程,使用附加参数 'i_showEmptyCarrier' 来指定是否需要隐藏或显示空载体。
+---------------------------+
| Carriers |
+----+----------+-----------+
| id | label | location |
+----+----------+-----------+
| 1 | carrier1 | warehouse |
+----+----------+-----------+
| 2 | carrier2 | warehouse |
+----+----------+-----------+
| 3 | carrier3 | factory |
+----+----------+-----------+
我需要查询 'products' table 以检查载体是否为空。
+-------------------------------------------+
| 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 |
+----+-----------+----------------+---------+
所以在这种情况下,carrier3 是空的。
我想要的存储过程逻辑是:
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;
所以如果 'i_showEmptyCarrier' = 1,那么 3 号空载机将被 selected,
+----------+--------------+
| label | nrOfProducts |
+----------+--------------+
| carrier3 | 0 |
+----------+--------------+
否则只有 1 号和 2 号运营商被 selected。
+----------+--------------+
| label | nrOfProducts |
+----------+--------------+
| carrier1 | 2 |
+----------+--------------+
| carrier2 | 2 |
+----------+--------------+
看来您受到了很多 Java(或其他编程语言)的影响。我不确定你到底想要什么。但这里是你如何实现你想要的。
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;
意味着您不需要 if-else 块来处理它。您可以在查询本身的 where 子句中执行此操作。
注意:我不知道您的 table 结构和集合细节。我猜它并发布代码。您可能需要相应地进行调整。
如何修改查询以使用 left join
和 conditional aggregation
最后比较输入,
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));
您仍然可以使用 where 子句代替 if-else。
您希望在一种情况下使用内部联接而在另一种情况下使用外部联接。由于外连接仅意味着 outer-joined 行的所有列都为空,但是,在这两种情况下您都可以简单地进行外连接,然后才决定是关闭还是保留 outer-joined 行。
在 SQL 中,这很简单:
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')
(当然,您可以将其汇总为 count(p.id)
。在这种情况下,您可以 group by c.id
或查看一个运营商 where c.id = :carrier_id
。)
我想为 select 载体编写一个存储过程,使用附加参数 'i_showEmptyCarrier' 来指定是否需要隐藏或显示空载体。
+---------------------------+
| Carriers |
+----+----------+-----------+
| id | label | location |
+----+----------+-----------+
| 1 | carrier1 | warehouse |
+----+----------+-----------+
| 2 | carrier2 | warehouse |
+----+----------+-----------+
| 3 | carrier3 | factory |
+----+----------+-----------+
我需要查询 'products' table 以检查载体是否为空。
+-------------------------------------------+
| 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 |
+----+-----------+----------------+---------+
所以在这种情况下,carrier3 是空的。
我想要的存储过程逻辑是:
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;
所以如果 'i_showEmptyCarrier' = 1,那么 3 号空载机将被 selected,
+----------+--------------+
| label | nrOfProducts |
+----------+--------------+
| carrier3 | 0 |
+----------+--------------+
否则只有 1 号和 2 号运营商被 selected。
+----------+--------------+
| label | nrOfProducts |
+----------+--------------+
| carrier1 | 2 |
+----------+--------------+
| carrier2 | 2 |
+----------+--------------+
看来您受到了很多 Java(或其他编程语言)的影响。我不确定你到底想要什么。但这里是你如何实现你想要的。
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;
意味着您不需要 if-else 块来处理它。您可以在查询本身的 where 子句中执行此操作。
注意:我不知道您的 table 结构和集合细节。我猜它并发布代码。您可能需要相应地进行调整。
如何修改查询以使用 left join
和 conditional aggregation
最后比较输入,
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));
您仍然可以使用 where 子句代替 if-else。
您希望在一种情况下使用内部联接而在另一种情况下使用外部联接。由于外连接仅意味着 outer-joined 行的所有列都为空,但是,在这两种情况下您都可以简单地进行外连接,然后才决定是关闭还是保留 outer-joined 行。
在 SQL 中,这很简单:
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')
(当然,您可以将其汇总为 count(p.id)
。在这种情况下,您可以 group by c.id
或查看一个运营商 where c.id = :carrier_id
。)