// Your own class Int
class Int { ... }
Int x = new Int(12);
int y = x; // auto-unboxing, not possible with Int
运行以下区块后,我会在屏幕上看到什么?
CREATE TABLE plch_test
(
x NUMBER
, y VARCHAR2 (3)
);
BEGIN
INSERT INTO plch_test
VALUES (1, 'NO');
INSERT INTO plch_test
VALUES (2, NULL);
COMMIT;
END;
/
CREATE OR REPLACE FUNCTION silly_function (p_x NUMBER)
RETURN VARCHAR2
IS
l_y plch_test.y%TYPE;
BEGIN
SELECT t.y
INTO l_y
FROM plch_test t
WHERE t.x = silly_function.p_x;
RETURN l_y;
END;
我认为第2行和第3行会抛出错误BEGIN
UPDATE plch_test SET y = 'YES' WHERE silly_function (x) != 'YES'; -- Line 2 Function call
select silly_function(x) from dual; -- Line 3
DBMS_OUTPUT.put_line ('Updated=' || SQL%ROWCOUNT);
EXCEPTION
WHEN VALUE_ERROR
THEN
DBMS_OUTPUT.put_line ('VALUE_ERROR');
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line ('OTHER_ERROR');
END;
/
。但是,当我执行上面的脚本第2行执行时,第3行引发了异常。谁能解释第2行和第3行之间的区别?
答案 0 :(得分:0)
第2行:
UPDATE plch_test SET y = 'YES' WHERE silly_function (x) != 'YES';
...会更新表格中的一行,即y
设置为'NO'
的行。另一行为空,因此不等于或不等于任何东西。 x
是有效的标识符,因为您指的是表plch_test
,其中包含具有该名称的列。为每行调用该函数,该行的值为x
。
第3行:
select silly_function(x) from dual;
...会出错,因为你没有选择任何东西,当然你必须在PL / SQL上下文中做。但是你也没有范围内的x
变量,所以它仍然会出错。
所以这不会出现错误(希望;未经测试):
DECLARE
l_x plch_test.x%type;
l_y plch_test.y%type;
BEGIN
UPDATE ... ;
l_x := 1;
select silly_function(l_x) into l_y from dual;
END;
你不是通过捕捉和压制你得到的实际例外来帮助自己,否则这将是非常明显的。
你也不需要在这里选择,因为你可以做一个任务:
l_y := silly_function(l_x);
在您发表评论并通过测试验证后,您所说的更新无效,因为它会抛出ORA-04091: table SCHEMA.PLCH_TEST is mutating, trigger/function may not see it
。您的更新将根据y
的当前值决定提供y
的值。但是,当前的价值是什么呢?是指在更新声明中间?在函数内部的选择中,Oracle应该使用哪个y
值 - 更新前或更新后的值?例外是有效地说它不能安全和一致地选择,所以你要求它做一些不安全和不一致的事情,这是RDBMS真正试图避免的。
一种方法是将查询/函数调用与更新分开,例如:使用游标循环:
DECLARE
CURSOR c IS
SELECT * FROM plch_test
WHERE silly_function (x) != 'YES'
FOR UPDATE;
BEGIN
--UPDATE plch_test SET y = 'YES' WHERE silly_function (x) != 'YES';
FOR r IN c LOOP
UPDATE plch_test SET y = 'YES' WHERE CURRENT OF c;
END LOOP;
END;
/
anonymous block completed
SELECT * FROM plch_test;
X Y
---------- ---
1 YES
2