【问题标题】:PL/SQL pre defined Statement in cursor definition游标定义中的PL/SQL预定义语句
【发布时间】:2017-08-10 12:13:22
【问题描述】:

我们有一个select 语句,它根据开关的不同而不同。然后我们循环遍历结果。

目前代码如下:

if switch_a then
    for rec in 
    (
        select * 
                order by decode(x, y,1,0),
                decode(x,a,2,0),
                decode(x,z,3,0), pos
    )
    loop ...
end loop;
else 
for rec in 
        (
            select * 
                    order by decode(x, y,1,0),
                    decode(x,z,3,0), pos
        )
        loop ...
end loop;
end if;

现在我想将该代码转换为只有一个循环。所以我选择:

if (switch_a) then
    Statement call := select*...
else
    Statement call := select*...
end if;

for rec in call
loop

end loop;

问题是,我不知道这是否适用于 for rec in 并且我不知道如何定义可执行的 SQL 语句。这可能吗?如果可以,你能举个例子吗?

【问题讨论】:

  • 似乎是解决方案的一部分。但是我必须在函数之外定义游标,这将不允许根据我从 If 子句获得的结果用两个不同的语句填充同一个游标。这将导致我仍然必须使用两个不同的循环,并且我不会获得更清晰的代码。我错过了什么吗?
  • 只是您的查询中的顺序不同吗?您的示例中没有包含 from 和 where 子句,因此很难判断。 I3rutt 的答案的替代方法是将两个循环中的所有逻辑拉到一个单独的过程中(带有必要的参数),然后您只需要从两个循环内部调用该过程。
  • 该语句仅在“order by”部分有所不同。如果开关为真,则有一个额外的按条件排序,

标签: sql loops plsql


【解决方案1】:

看到只是顺序不同,我会使用非布尔值(SQL 不知道 Oracle 中的布尔值)标志来决定是否将列包含在 order by 中,例如:

WITH sample_data AS (SELECT 1 col1, 100 col2, 200 col3 FROM dual UNION ALL
                     SELECT 2 col1, 90 col2, 210 col3 FROM dual UNION ALL
                     SELECT 3 col1, 80 col2, 220 col3 FROM dual UNION ALL
                     SELECT 4 col1, 70 col2, 230 col3 FROM dual UNION ALL
                     SELECT 5 col1, 60 col2, 240 col3 FROM dual)
SELECT col1,
       col2,
       col3
FROM   sample_data
ORDER BY CASE WHEN :p_switch_a_flag = 'y' THEN col2 END,
         col3;

使用 :p_switch_a_flag = 'n' 运行它:

      COL1       COL2       COL3
---------- ---------- ----------
         1        100        200
         2         90        210
         3         80        220
         4         70        230
         5         60        240

使用:p_switch_a_flag = 'y' 运行它:

      COL1       COL2       COL3
---------- ---------- ----------
         5         60        240
         4         70        230
         3         80        220
         2         90        210
         1        100        200

这样,无论标志是如何设置的,您都只有一个光标,并且您的代码看起来像:

-- if you can't change the switch_a Boolean to a varchar2 flag, then
-- manually set the switch_a flag, otherwise you'd simply pass in
-- the flag as a varchar2, rather than a Boolean.
if switch_a then 
  switch_a_flag := 'y';
end if;

for rec in (select * 
            from    ....
            order by decode(x, y,1,0),
                     case when switch_a_flag = 'y' then decode(x,a,2,0) end,
                     decode(x,z,3,0),
                     pos)
loop
  ...
end loop;

【讨论】:

    【解决方案2】:

    可能是这样的:

    declare 
      Statement_call varchar2(4000); 
      rec sys_refcursor;  
      l_row number;
    begin
        if (switch_a) then
          Statement_call := 'select 1 as q from dual';
        else
          Statement_call := 'select 2 as q from dual';
        end if;
    
        OPEN rec FOR Statement_call;
        loop
          FETCH rec INTO l_row;
          EXIT WHEN rec%NOTFOUND;
    
          dbms_output.put_line(l_row);
        end loop;   
        CLOSE rec;
    
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-02
      • 2018-03-13
      • 1970-01-01
      • 1970-01-01
      • 2020-06-16
      • 1970-01-01
      相关资源
      最近更新 更多