Oracle PL/SQL 下面的代码为啥出错啊!提示CASE与WHEN见出现不匹配字符,急!

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle PL/SQL 下面的代码为啥出错啊!提示CASE与WHEN见出现不匹配字符,急!相关的知识,希望对你有一定的参考价值。

declare
c_id number;
c_name varchar2(20);
c_level number;
c_turnover number;
cursor c is
select
id,name,turnover,levels from client;
begin
open c;
loop
fetch c into c_id,c_name,c_turnover,c_level;
exit when c%NOTFOUND;
case c_turnover
when (c_turnover>=500000) AND (c_turnover<=1000000) then
update client set levels = levels + 2 where id=c_id;
when (c_turnover<500000) AND (c_turnover>=200000) then
update client set levels = level + 1 where id=c_id;
when c_turnover< 100000 then
update client set levels = levels - 1 where id=c_id;
end case;
end loop;
close c;
end;

case c_turnover 表明下面会直接列举取值
你下面的条件里面有case c_turnover<500000
因此,上面case c_turnover多余了,直接写case追问

会提示没有找到CASE,改用if...elsif语句的话,又提示需要connect by 子句
if (c_turnover>=500000) AND (c_turnover=200000) then
update client set levels = level + 1 where id=c_id;
end if;

追答

declare
c_id number;
c_name varchar2(20);
c_level number;
c_turnover number;
cursor c is
select
id,name,turnover,levels from client;
begin
open c;
loop
fetch c into c_id,c_name,c_turnover,c_level;
exit when c%NOTFOUND;
-- case c_turnover
case
when (c_turnover>=500000) AND (c_turnover=200000) then
-- update client set levels = level + 1 where id=c_id;
update client set levels = level + 1 where id= :c_id;
when c_turnover< 100000 then
-- update client set levels = levels - 1 where id= c_id;
update client set levels = levels - 1 where id= :c_id;
end case;
end loop;
close c;
end;

参考技术A 声明 c_turnover number时;
改成c_turnover number(7,0);追问

还是不行啊高手... 而且改成if...elsif时又提示要用connect by子句...费解

追答

把那个case 后面的去掉

追问

会提示没有找到CASE,改用if...elsif语句的话,又提示需要connect by 子句
if (c_turnover>=500000) AND (c_turnover=200000) then
update client set levels = level + 1 where id=c_id;
end if;

追答

if (c_turnover>=500000 && c_turnover=200000) then
update client set levels = level + 1 where id=c_id;
end if;

在 Oracle PL/SQL 中重用绑定变量

【中文标题】在 Oracle PL/SQL 中重用绑定变量【英文标题】:Re-using bind variables in Oracle PL/SQL 【发布时间】:2012-07-26 00:12:37 【问题描述】:

我有一个带有联合的大量 SQL 语句,其中代码不断被重用。我希望找出是否有一种方法可以重用单个绑定变量,而无需多次重复该变量以“使用”。

在我将“USING”行更改为“USING VAR1,VAR2,VAR1;”之前,下面的代码会返回“并非所有变量都绑定”

我希望避免这种情况,因为我在这两种情况下都提到 :1 - 有什么想法吗?

declare
var1 number :=1;
var2 number :=2;
begin
execute immediate '
select * from user_objects 
where 
rownum = :1
OR rownum = :2  
OR rownum = :1 '
using var1,var2;
end;
/

编辑:有关更多信息,我正在使用动态 SQL,因为我还生成了一系列 where 条件。

我不擅长使用 SQL 数组(我在代码中使用游标,但我认为这会使问题过于复杂),但伪代码是:

v_where varchar2(100) :='';
FOR i in ('CAT','HAT','MAT') LOOP
  v_where := v_where || ' OR OBJECT_NAME LIKE ''%' || i.string ||'%''
END;
  v_where := ltrim(v_where, ' OR');

然后将上面的 SQL 修改为:

execute immediate '
select * from user_objects 
where 
rownum = :1
OR rownum = :2  
OR rownum = :1 AND ('||V_WHERE||')'
using var1,var2;

【问题讨论】:

【参考方案1】:

您可能会考虑一些选项,尽管它们可能需要更改执行 SQL 语句的方式或 SQL 语句本身。

    使用DBMS_SQL 而不是EXECUTE IMMEDIATE -- DBMS_SQL(参见http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm)比EXECUTE IMMEDIATE 更难使用,但可以让您更好地控制流程——包括能力(通过DBMS_SQL.BIND_VARIABLEDBMS_SQL.BIND_ARRAY) 按名称而不是按位置绑定。 EXECUTE IMMEDIATEWITH 子句一起使用 -- 您可以重组查询以使用WITH 子句在开始时在子查询中收集绑定变量,然后加入子查询(而不是直接引用绑定变量)在需要它们时。它可能看起来像这样
with your_parameters as 
    (select :1 as p1, :2 as p2 from dual) 
select * 
from your_table, your_parameters 
where your_table.some_column1 = your_parameters.p1 
  and your_table.some_column2 <= your_parameters.p1 
  and your_table.some_column3 = your_parameters.p2

这可能会影响查询的性能,但它可能是一个可以接受的折衷方案。

    不要使用动态SQL -- 当然,如果你不需要动态SQL,你不需要使用EXECUTE IMMEDIATE,所以“仅按位置绑定”的限制不适用。你确定你真的需要使用动态 SQL 吗?

编辑:如果您使用动态 SQL,因为您在编辑中发布的 OR 条件数量不定,您可以通过执行以下操作之一来避免使用动态 SQL:

    如果OR 条件来自表(或查询) - 加入该表(或查询),而不是使用OR 条件列表。例如,如果 CAT、HAT 和 MAT 列在名为 YOUR_CRITERIA_TABLE 的表中名为 YOUR_CRITERIA 的列中,则可以将 YOUR_CRITERIA_TABLE 添加到 FROM 子句并替换 WHERE 子句中的 OBJECT_NAME LIKE '%CAT% OR OBJECT_NAME LIKE '%MAT% OR OBJECT_NAME LIKE '%HAT% OR OBJECT_NAME LIKE '%MAT%类似OBJECT_NAME LIKE '%' || YOUR_CRITERIA_TABLE.YOUR_CRITERIA || '%'. 否则,您可能会将条件放在全局临时表中 -- 如果您的条件不是来自表(或查询),您可以(一次,在设计时,而不是在运行时)创建一个全局临时表来保存它们,然后在运行时将条件插入到全局临时表中,然后按照第 1 项中的说明加入它。 或者,您可以将条件放在嵌套表中 -- 这与第 2 项类似,不同之处在于使用嵌套表(使用CREATE TYPE...IS TABLE OF 创建的表)而不是全局临时表。您可以创建或拥有嵌套表类型,或使用像SYS.ODCIVARCHAR2LIST 这样的内置表类型。在 PL/SQL 中,您将填充此类型的变量,然后像第 1 项中的“真实”表一样使用它。

第 3 项的示例可能类似于:

DECLARE
    tblCriteria SYS.ODCIVARCHAR2LIST;

BEGIN
    tblCriteria := SYS.ODCIVARCHAR2LIST();

    -- In "real" code you might populate the nested table in a loop.
    -- This example populates it explicitly so that it will compile.  For the
    -- purpose of the example, we could have populated the nested table in 
    -- a single statement:

    -- tblCriteria := SYS.ODCIVARCHAR2LIST('CAT', 'HAT', 'MAT');

    tblCriteria.EXTEND(1);
    tblCriteria(tblCriteria.LAST) := 'CAT';

    tblCriteria.EXTEND(1);
    tblCriteria(tblCriteria.LAST) := 'HAT';

    tblCriteria.EXTEND(1);
    tblCriteria(tblCriteria.LAST) := 'MAT';

    FOR rec IN
    (
        SELECT
            USER_OBJECTS.*
        FROM
            USER_OBJECTS,
            TABLE(tblCriteria) YOUR_NESTED_TABLE
        WHERE
            USER_OBJECTS.OBJECT_NAME LIKE '%' || YOUR_NESTED_TABLE.COLUMN_VALUE || '%'
    )
    LOOP
        -- Do something.  For example, print out the object name.
        DBMS_OUTPUT.PUT_LINE(rec.OBJECT_NAME);
    END LOOP;
END;

【讨论】:

我真的很感激这个细节 - 也许你可以为我回答问题 3。我目前有一个变量数组,它们变成了一个连接的 where 子句条件,不幸的是我根本无法将它变成一个绑定变量......我将在原始问题中添加细节...... 我已经编辑了我的原始答案以(希望)解决您添加的详细信息。【参考方案2】:

不,不幸的是,EXECUTE IMMEDIATE 的绑定变量必须按照它们在语句中出现的顺序提供,并且绑定变量名称被忽略。因此,您只需要在语句中包含 :1、:2 和 :3。

【讨论】:

该死,我有两个变量每个重复 5 次。我会看看我是否可以更好地重写代码。谢谢!

以上是关于Oracle PL/SQL 下面的代码为啥出错啊!提示CASE与WHEN见出现不匹配字符,急!的主要内容,如果未能解决你的问题,请参考以下文章

pl/sql developer中文乱码,为啥呢?怎么解决?Oracle问题

pl/sql developer中文乱码,为啥呢?怎么解决?Oracle问题

pl/sql developer中文乱码,为啥呢?怎么解决?Oracle问题

pl/sql连接oracle数据库tables里面不显示表。

oracle PL/SQL语句题目求教!

为啥mssql的OPENQUERY取oracle某表时只返回了一行数据,而在pl/sql中可以查到表中有两行数据,求解答?