存储过程中的 Oracle 条件 WHERE

Posted

技术标签:

【中文标题】存储过程中的 Oracle 条件 WHERE【英文标题】:Oracle conditional WHERE in stored procedure 【发布时间】:2020-09-10 13:42:29 【问题描述】:

我想编写一个存储过程来选择运营商,并带有一个附加参数“i_showEmptyCarrier”来指定是否需要隐藏或显示空运营商。

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

我需要查询“产品”表以检查载体是否为空。

+-------------------------------------------+
|                  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 号,

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

否则只选择 1 号和 2 号运营商。

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

【问题讨论】:

您好,请提供表结构和示例数据。然后告诉我们您希望如何选择行。 【参考方案1】:

如何修改查询以使用left joinconditional 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。

【讨论】:

@cfoppa,我可以知道您不接受答案背后的原因只是为了更好地理解吗?了解这里对我来说非常重要。 @cfoppa 接受的解决方案不考虑deleted_flag,我不知道它如何解决您的原始问题。【参考方案2】:

您希望在一种情况下使用内部联接,而在另一种情况下使用外部联接。由于外连接只是意味着外连接行的所有列都为空,但是,您可以在这两种情况下简单地进行外连接,然后才决定是关闭还是保留外连接行。

在 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。)

【讨论】:

【参考方案3】:

看来您对 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 子句中执行此操作。

注意:我不知道您的表结构和集合详细信息。我猜它并发布代码。您可能需要相应地调整它。

【讨论】:

您好,我添加了我正在使用的表格,感谢您回答我的问题!

以上是关于存储过程中的 Oracle 条件 WHERE的主要内容,如果未能解决你的问题,请参考以下文章

oracle过程中查询语句where条件中带变量怎么实现?

在oracle中创建带参存储过程,传进去的参数可以为空么?在存储过程中要如何判断传进来的值是不是为空。

在 PL/SQL 存储过程中将多个变量传递给 WHERE 条件

存储过程(Informix)中的自定义“WHERE”?

在 ORACLE 中的 WHERE 中传递多值 [重复]

oracle索引视图存储过程触发器oracle数据类型