根据变量的值从同一个查询中得到不同的结果
getting different results from the same query according to the value of a variable
假设我们有以下主数据:
order_type: [classic, transport]
order_status: [new, active, delivered, finished]
我们有订单 tables:
+----------+------------+--------------+
| order_id | order_type | order_status |
+==========+============+==============+
| 1 | classic | new |
+----------+------------+--------------+
| 2 | classic | active |
+----------+------------+--------------+
| 3 | transport | active |
+----------+------------+--------------+
| 4 | transport | delivered |
+----------+------------+--------------+
| 5 | classic | finished |
+----------+------------+--------------+
| 6 | classic | active |
+----------+------------+--------------+
| 7 | transport | delivered |
+----------+------------+--------------+
| 8 | classic | finished |
+----------+------------+--------------+
请求的是根据给定变量的值 v_order_status
:
进行一个查询,该查询可以 return 2 组不同的数据
v_order_status = 'del'
然后只检索 运输订单:
+----------+------------+--------------+
| order_id | order_type | order_status |
+==========+============+==============+
| 3 | transport | active |
+----------+------------+--------------+
| 4 | transport | delivered |
+----------+------------+--------------+
| 7 | transport | delivered |
+----------+------------+--------------+
v_order_status =
any other value or null
然后我们检索整个 table.
所需的 SQL 语句将在存储过程中使用,例如:
procedure process_orders (v_order_status in varchar2(3) default null)
as
begin
for ord in (select order_id, order_type, order_status
from orders
where [here comes the tricky part])
loop
do_something (ord.order_id);
...
end loop;
end process_orders ;
知道如何在 SQL 语句中设置 where
子句吗?
使用布尔逻辑:
select order_id, order_type, order_status
from orders
where
(v_order_status = 'del' and order_type = 'transport')
or v_order_status <> 'del'
or v_order_status is null
WHERE (v_order_status='del' AND order_type= 'transport')
OR (v_order_status <> 'del' OR v_order_status is null)
我假设存储过程语言是PL/SQL。
不要将v_order定义为默认null,如果需要则默认'active'
只需在where条件中使用变量
procedure process_orders(v_order_status in varchar2(3) )
as
begin
for ord in (select order_id, order_type, order_status
from orders
where order_status = v_order_status
loop
do_something (ord.order_id);
...
end loop;
end process_orders ;
因为你在一个过程中,你应该利用它来使 select 语句尽可能简单。不要使用复杂的 where 子句(这可能会导致性能问题)创建查询,您应该在 PL/SQL 代码中执行您需要的任何逻辑,然后执行一个简单的查询。
在下面的示例中,我创建了一个局部变量,它根据您描述的条件设置了值,然后将该变量用作 where 子句中的唯一条件。我添加了 NVL (order_type, 'no_order_type')
逻辑,以防万一有没有订单类型的订单,但如果那不可能,那么您可以从 where 子句中删除 NVL
。
例子
DECLARE
PROCEDURE process_orders (p_order_status IN VARCHAR2 DEFAULT NULL)
AS
l_order_type VARCHAR2 (20)
:= CASE p_order_status WHEN 'del' THEN 'transport' ELSE NULL END;
BEGIN
FOR ord
IN (SELECT order_id, order_type, order_status
FROM (SELECT 1 AS order_id, 'classic' AS order_type, 'new' AS order_status
FROM DUAL
UNION ALL
SELECT 2, 'classic', 'active' FROM DUAL
UNION ALL
SELECT 3, 'transport', 'active' FROM DUAL
UNION ALL
SELECT 4, 'transport', 'delivered' FROM DUAL
UNION ALL
SELECT 5, 'classic', 'finished' FROM DUAL
UNION ALL
SELECT 6, 'classic', 'active' FROM DUAL
UNION ALL
SELECT 7, 'transport', 'delivered' FROM DUAL
UNION ALL
SELECT 8, 'classic', 'finished' FROM DUAL) orders
WHERE NVL (order_type, 'no_order_type') =
NVL (l_order_type, NVL (order_type, 'no_order_type')))
LOOP
--do_something (ord.order_id);
DBMS_OUTPUT.put_line ('Order ID: ' || ord.order_id);
END LOOP;
END process_orders;
BEGIN
DBMS_OUTPUT.put_line ('Status: something');
process_orders ('something');
DBMS_OUTPUT.put_line ('Status: del');
process_orders ('del');
DBMS_OUTPUT.put_line ('Status: null');
process_orders (NULL);
END;
输出
Status: something
Order ID: 1
Order ID: 2
Order ID: 3
Order ID: 4
Order ID: 5
Order ID: 6
Order ID: 7
Order ID: 8
Status: del
Order ID: 3
Order ID: 4
Order ID: 7
Status: null
Order ID: 1
Order ID: 2
Order ID: 3
Order ID: 4
Order ID: 5
Order ID: 6
Order ID: 7
Order ID: 8
作为提供的所有解决方案的替代方案,另一种选择是使用动态 sql 并将 for loop
结构更改为 bulk collect
。这就是多行查询的动态 SQL。
类似的东西应该适用于你的情况。
测试用例元素
SQL> create table orders ( order_id number, order_type varchar2(20) , order_status varchar2(20) ) ;
Table created.
SQL> insert into orders
2 with t ( order_id , order_type, order_status )
3 as
4 (
5 select 1, 'classic' , 'del' from dual union all
6 select 2, 'classic' , 'del' from dual union all
7 select 3, 'transport' , 'act' from dual union all
8 select 4, 'transport' , 'act' from dual union all
9 select 5, 'transport' , 'fin' from dual union all
10 select 6, 'classic' , 'fin' from dual union all
11 select 7, 'classic' , 'fin' from dual union all
12 select 8, 'transport' , 'act' from dual union all
13 select 9, 'transport' , 'act' from dual
14 )
15 select * from t ;
9 rows created.
SQL>
SQL> commit;
Commit complete.
SQL>
SQL> create or replace procedure process_orders ( v_order_status in varchar2 default null )
2 is
3 TYPE order_rt IS RECORD (
4 order_id number,
5 order_type varchar2(20),
6 order_status varchar2(20)
7 );
8
9 TYPE order_rt_aat IS TABLE OF order_rt INDEX BY PLS_INTEGER;
10
11 l_orders order_rt_aat;
12 v_sql clob;
13 BEGIN
14
15 v_sql := q'[ select order_id, order_type, order_status from orders ]' ;
16 if v_order_status is not null
17 then
18 v_sql := v_sql || ' where order_status = '''||v_order_status||''' ';
19 end if;
20
21 execute immediate v_sql bulk collect into l_orders;
22
23 FOR indx IN 1 .. l_orders.COUNT
24 LOOP
25 DBMS_OUTPUT.put_line (l_orders (indx).order_id);
26 END LOOP;
27 END;
28 /
Procedure created.
SQL>
验证
运行 无入参
SQL> set serveroutput on
SQL> exec process_orders ;
1
2
3
4
5
6
7
8
9
PL/SQL procedure successfully completed.
运行 带有特定的输入参数
SQL> exec process_orders ( 'del' ) ;
1
2
PL/SQL procedure successfully completed.
同意使用 where
子句的其他答案完全没问题,
正如这个特殊要求所说 v_order_status = 'del'
然后只检索运输订单 v_order_status =any other value or null
然后我们检索整个 table,为此我们也可以使用decode 作为一行语句,
The Oracle docs note the following about the decode SQL function:
"DECODE compares a column or expression to search values, returning a result when there is a match. DECODE is similar to IF_THEN-ELSE logic."
select *
from
(
select 1 order_id,'classic' order_type,'new' order_status from dual
union all
select 2,'classic','active' from dual
union all
select 3,'transport','active' from dual
union all
select 4,'transport','delivered' from dual
)
where order_type = decode(&v_order_status,'del','transport',order_type);
假设我们有以下主数据:
order_type: [classic, transport]
order_status: [new, active, delivered, finished]
我们有订单 tables:
+----------+------------+--------------+
| order_id | order_type | order_status |
+==========+============+==============+
| 1 | classic | new |
+----------+------------+--------------+
| 2 | classic | active |
+----------+------------+--------------+
| 3 | transport | active |
+----------+------------+--------------+
| 4 | transport | delivered |
+----------+------------+--------------+
| 5 | classic | finished |
+----------+------------+--------------+
| 6 | classic | active |
+----------+------------+--------------+
| 7 | transport | delivered |
+----------+------------+--------------+
| 8 | classic | finished |
+----------+------------+--------------+
请求的是根据给定变量的值 v_order_status
:
v_order_status = 'del'
然后只检索 运输订单:+----------+------------+--------------+ | order_id | order_type | order_status | +==========+============+==============+ | 3 | transport | active | +----------+------------+--------------+ | 4 | transport | delivered | +----------+------------+--------------+ | 7 | transport | delivered | +----------+------------+--------------+
v_order_status =
any other value or null
然后我们检索整个 table.
所需的 SQL 语句将在存储过程中使用,例如:
procedure process_orders (v_order_status in varchar2(3) default null)
as
begin
for ord in (select order_id, order_type, order_status
from orders
where [here comes the tricky part])
loop
do_something (ord.order_id);
...
end loop;
end process_orders ;
知道如何在 SQL 语句中设置 where
子句吗?
使用布尔逻辑:
select order_id, order_type, order_status
from orders
where
(v_order_status = 'del' and order_type = 'transport')
or v_order_status <> 'del'
or v_order_status is null
WHERE (v_order_status='del' AND order_type= 'transport')
OR (v_order_status <> 'del' OR v_order_status is null)
我假设存储过程语言是PL/SQL。
不要将v_order定义为默认null,如果需要则默认'active'
只需在where条件中使用变量
procedure process_orders(v_order_status in varchar2(3) ) as begin for ord in (select order_id, order_type, order_status from orders where order_status = v_order_status loop do_something (ord.order_id); ... end loop; end process_orders ;
因为你在一个过程中,你应该利用它来使 select 语句尽可能简单。不要使用复杂的 where 子句(这可能会导致性能问题)创建查询,您应该在 PL/SQL 代码中执行您需要的任何逻辑,然后执行一个简单的查询。
在下面的示例中,我创建了一个局部变量,它根据您描述的条件设置了值,然后将该变量用作 where 子句中的唯一条件。我添加了 NVL (order_type, 'no_order_type')
逻辑,以防万一有没有订单类型的订单,但如果那不可能,那么您可以从 where 子句中删除 NVL
。
例子
DECLARE
PROCEDURE process_orders (p_order_status IN VARCHAR2 DEFAULT NULL)
AS
l_order_type VARCHAR2 (20)
:= CASE p_order_status WHEN 'del' THEN 'transport' ELSE NULL END;
BEGIN
FOR ord
IN (SELECT order_id, order_type, order_status
FROM (SELECT 1 AS order_id, 'classic' AS order_type, 'new' AS order_status
FROM DUAL
UNION ALL
SELECT 2, 'classic', 'active' FROM DUAL
UNION ALL
SELECT 3, 'transport', 'active' FROM DUAL
UNION ALL
SELECT 4, 'transport', 'delivered' FROM DUAL
UNION ALL
SELECT 5, 'classic', 'finished' FROM DUAL
UNION ALL
SELECT 6, 'classic', 'active' FROM DUAL
UNION ALL
SELECT 7, 'transport', 'delivered' FROM DUAL
UNION ALL
SELECT 8, 'classic', 'finished' FROM DUAL) orders
WHERE NVL (order_type, 'no_order_type') =
NVL (l_order_type, NVL (order_type, 'no_order_type')))
LOOP
--do_something (ord.order_id);
DBMS_OUTPUT.put_line ('Order ID: ' || ord.order_id);
END LOOP;
END process_orders;
BEGIN
DBMS_OUTPUT.put_line ('Status: something');
process_orders ('something');
DBMS_OUTPUT.put_line ('Status: del');
process_orders ('del');
DBMS_OUTPUT.put_line ('Status: null');
process_orders (NULL);
END;
输出
Status: something
Order ID: 1
Order ID: 2
Order ID: 3
Order ID: 4
Order ID: 5
Order ID: 6
Order ID: 7
Order ID: 8
Status: del
Order ID: 3
Order ID: 4
Order ID: 7
Status: null
Order ID: 1
Order ID: 2
Order ID: 3
Order ID: 4
Order ID: 5
Order ID: 6
Order ID: 7
Order ID: 8
作为提供的所有解决方案的替代方案,另一种选择是使用动态 sql 并将 for loop
结构更改为 bulk collect
。这就是多行查询的动态 SQL。
类似的东西应该适用于你的情况。
测试用例元素
SQL> create table orders ( order_id number, order_type varchar2(20) , order_status varchar2(20) ) ;
Table created.
SQL> insert into orders
2 with t ( order_id , order_type, order_status )
3 as
4 (
5 select 1, 'classic' , 'del' from dual union all
6 select 2, 'classic' , 'del' from dual union all
7 select 3, 'transport' , 'act' from dual union all
8 select 4, 'transport' , 'act' from dual union all
9 select 5, 'transport' , 'fin' from dual union all
10 select 6, 'classic' , 'fin' from dual union all
11 select 7, 'classic' , 'fin' from dual union all
12 select 8, 'transport' , 'act' from dual union all
13 select 9, 'transport' , 'act' from dual
14 )
15 select * from t ;
9 rows created.
SQL>
SQL> commit;
Commit complete.
SQL>
SQL> create or replace procedure process_orders ( v_order_status in varchar2 default null )
2 is
3 TYPE order_rt IS RECORD (
4 order_id number,
5 order_type varchar2(20),
6 order_status varchar2(20)
7 );
8
9 TYPE order_rt_aat IS TABLE OF order_rt INDEX BY PLS_INTEGER;
10
11 l_orders order_rt_aat;
12 v_sql clob;
13 BEGIN
14
15 v_sql := q'[ select order_id, order_type, order_status from orders ]' ;
16 if v_order_status is not null
17 then
18 v_sql := v_sql || ' where order_status = '''||v_order_status||''' ';
19 end if;
20
21 execute immediate v_sql bulk collect into l_orders;
22
23 FOR indx IN 1 .. l_orders.COUNT
24 LOOP
25 DBMS_OUTPUT.put_line (l_orders (indx).order_id);
26 END LOOP;
27 END;
28 /
Procedure created.
SQL>
验证
运行 无入参
SQL> set serveroutput on
SQL> exec process_orders ;
1
2
3
4
5
6
7
8
9
PL/SQL procedure successfully completed.
运行 带有特定的输入参数
SQL> exec process_orders ( 'del' ) ;
1
2
PL/SQL procedure successfully completed.
同意使用 where
子句的其他答案完全没问题,
正如这个特殊要求所说 v_order_status = 'del'
然后只检索运输订单 v_order_status =any other value or null
然后我们检索整个 table,为此我们也可以使用decode 作为一行语句,
The Oracle docs note the following about the decode SQL function: "DECODE compares a column or expression to search values, returning a result when there is a match. DECODE is similar to IF_THEN-ELSE logic."
select *
from
(
select 1 order_id,'classic' order_type,'new' order_status from dual
union all
select 2,'classic','active' from dual
union all
select 3,'transport','active' from dual
union all
select 4,'transport','delivered' from dual
)
where order_type = decode(&v_order_status,'del','transport',order_type);