我想使用pl / sql函数更新下表,事情是我设法编写了一个触发器代码,但我想用'function'重新编写它。 我希望客户5将订单从30增加到200.并允许用户输入:
1)customer_ID和的数字5 2)200更新数量。 并在更新前后打印出客户5的总数量。
Create table sales (customer_ID number(10), product_ID number(10), quantity number(10));
INSERT INTO sales (customer_ID, product_ID, quantity) Values(3,1,23);
INSERT INTO sales (customer_ID, product_ID, quantity) Values(1,2,34);
INSERT INTO sales (customer_ID, product_ID, quantity) Values(1,3,654);
INSERT INTO sales (customer_ID, product_ID, quantity) Values(3,7,32);
INSERT INTO sales (customer_ID, product_ID, quantity) Values(4,3,23);
INSERT INTO sales (customer_ID, product_ID, quantity) Values(3,3,111);
INSERT INTO sales (customer_ID, product_ID, quantity) Values(5,4,6);
我写的触发码:
create or replace trigger quantity_change
before insert or update of quantity on sales
for each row
WHEN (NEW.customer_id > 0)
DECLARE
qua number;
BEGIN
qua := :NEW.quantity - :OLD.quantity;
dbms_output.put_line('Old quangtity: ' || :OLD.quantity);
dbms_output.put_line('New quantity: ' || :NEW.quantity);
dbms_output.put_line('diiference quangtity: ' || qua);
END;
UPDATE sales
SET quantity = 200 WHERE customer_id = 5;
我设法写了这个程序,但仍然卡住了,不知道如何启用
CREATE or replace PROCEDURE Updatesales
(
customer_ID number,
product_ID number,
quantity number)
AS
BEGIN
UPDATE sales
SET quantity= 100
WHERE customer_id= 4;
END;
我想使用一个函数来解决这个问题,一个函数就像这样的事情
CREATE [OR REPLACE] FUNCTION function_name [(parameter_name [IN | OUT | IN OUT] type [, ...])]
RETURN return_datatype {IS | AS} BEGIN < function_body > END [function_name];
请咨询
答案 0 :(得分:1)
您的程序未使用您声明的参数;身体应该更像:
UPDATE sales
SET quantity= quantity
WHERE customer_id= customer_id;
...但是这不符合您的期望,因为您对参数和列使用了相同的名称(并且根本没有引用产品ID),因此表中的每一行都会更新以其当前价值。通常使用正式参数名称的前缀来避免这种混淆,尽管在引用它们时也可以明确地使用过程名称。
你说你想要一个功能,但不清楚为什么。在程序中而不是在函数中修改数据是常规的,如果函数确实执行任何DML,则无法从查询中调用它,并且必须在PL / SQL上下文中调用它。所以我将从一个程序开始。
你说你想在更新前后打印出数量。程序不应该这样做;您不应该假设用户或客户端可以处理dbms_output或将其启用。您可以使用OUT参数将更新前的值返回给调用者:
CREATE OR REPLACE PROCEDURE update_sales
(
p_customer_id IN sales.customer_id%type,
p_product_id IN sales.product_id%type,
p_new_quantity IN sales.quantity%type,
p_old_quantity OUT sales.quantity%type
) AS
BEGIN
SELECT quantity
INTO p_old_quantity
FROM sales
WHERE customer_id = p_customer_id
AND product_id = p_product_id
FOR UPDATE;
UPDATE sales
SET quantity = p_new_quantity
WHERE customer_id = p_customer_id
AND product_id = p_product_id;
END;
/
这会将数量的当前值转换为OUT变量,并且还会使用for update
锁定记录,以便在您处理它时停止更改值(这可能是过度杀伤,但您想学习。 ..)
然后使用传入的新值更新同一行。即使用客户和产品ID再次查找行,如果要进行实验,可以采用不同的方式 - 将rowid放入另一个局部变量从您的第一个查询,并使用它进行更新,或使用光标等
您可以从匿名块中将其作为测试进行调用,并使用dbms_output显示旧值和新值;再次,不要在生产代码中使用dbms_output,仅用于调试:
SET serveroutput ON
DECLARE
l_customer_id sales.customer_id%type;
l_product_id sales.product_id%type;
l_new_quantity sales.quantity%type;
l_old_quantity sales.quantity%type;
BEGIN
l_customer_id := 5;
l_product_id := 4;
l_new_quantity := 200;
update_sales(l_customer_id, l_product_id, l_new_quantity, l_old_quantity);
dbms_output.put_line('Quantity changed from ' || l_old_quantity
|| ' to ' || l_new_quantity
|| ' (' || to_char(l_new_quantity - l_old_quantity, 'FMS999') || ')');
END;
/
PL/SQL procedure successfully completed.
Quantity changed from 6 to 200 (+194)
您可以使用绑定变量以类似的方式从应用程序调用此方法,并让应用程序显示值。
请注意,我没有提交或回滚更改,并且尝试使用相同值调用该过程的另一个会话将阻塞,直到我这样做;但是当它运行时会看到新值(200)。我还没有在过程中进行任何验证或异常处理,因此调用者需要同时执行这两项操作。
你可以使这个函数返回旧的值而不是使用OUT参数,但你需要以类似的方式调用它,通常人们不希望函数改变任何东西 - 只是为了返回当前状态。但如果你真的想要这样做,你需要修改声明以获得返回类型和局部变量;选择旧值到该局部变量;然后返回:
CREATE OR REPLACE FUNCTION update_sales
(
p_customer_id IN sales.customer_id%type,
p_product_id IN sales.product_id%type,
p_new_quantity IN sales.quantity%type
)
RETURN sales.quantity%type
AS
l_old_quantity sales.quantity%type;
BEGIN
SELECT quantity
INTO l_old_quantity
FROM sales
WHERE customer_id = p_customer_id
AND product_id = p_product_id;
UPDATE sales
SET quantity = p_new_quantity
WHERE customer_id = p_customer_id
AND product_id = p_product_id;
RETURN l_old_quantity;
END;
/
您仍然需要从PL / SQL上下文(或类似JDBC可调用语句)调用它:
DECLARE
l_old_quantity sales.quantity%type;
BEGIN
l_old_quantity := update_sales(5, 4, 200);
dbms_output.put_line('Quantity was ' || l_old_quantity);
END;
/
PL/SQL procedure successfully completed.
Quantity was 6
你不能从普通的SQL中调用它,因为它正在进行DML操作:
select update_sales(5, 4, 200) from dual;
Error report -
SQL Error: ORA-14551: cannot perform a DML operation inside a query
ORA-06512: at "MY_SCHEMA.UPDATE_SALES", line 17
14551. 00000 - "cannot perform a DML operation inside a query "
*Cause: DML operation like insert, update, delete or select-for-update
cannot be performed inside a query or under a PDML slave.
*Action: Ensure that the offending DML operation is not performed or
use an autonomous transaction to perform the DML operation within
the query or PDML slave.
答案 1 :(得分:0)
我从您的问题中了解到,只要在SALES表中插入新记录,您就希望自动更新客户数量5到200.
触发码: -
CREATE OR REPLACE TRIGGER quantity_change
before insert on sales
for each row
WHEN (NEW.customer_id > 0)
DECLARE
var number;
BEGIN
var:=update_sales(:new.customer_id,:new.quantity);
:new.quantity:=var;
END;
功能代码: -
CREATE OR REPLACE FUNCTION update_sales(CUSTOMER_ID NUMBER,ORIG_QUANT NUMBER) RETURN NUMBER IS RETURNVALUE NUMBER;
BEGIN
IF customer_id = 5 THEN
returnvalue:=200;
RETURN returnvalue;
ELSE
returnvalue:= orig_quant;
RETURN returnvalue;
END IF;
END;
对不起,如果我不明白的话。
此致 安迪
答案 2 :(得分:0)
所以现在我所做的是我从一个过程调用一个函数(因为我无法打印所有三个值而创建过程),从我这边做了一些假设。
create or replace FUNCTION QUANTITY_CHANGE_NEW (CUSTOMER NUMBER, QUANT NUMBER) RETURN NUMBER
IS PRAGMA AUTONOMOUS_TRANSACTION;
old_quantity NUMBER;
BEGIN
select quantity into old_quantity from sales where customer_id=customer and rownum=1;
update sales set quantity=quant where customer_id= customer;
COMMIT;
RETURN old_quantity;
END;
CREATE OR REPLACE PROCEDURE PROCEDURE1(customer IN NUMBER, new_quantity IN NUMBER) IS
var1 NUMBER;
BEGIN
dbms_output.put_line('Customer Id is ' || customer);
var1 := QUANTITY_CHANGE_NEW(customer,new_quantity);
dbms_output.put_line('old quantity is '|| var1);
dbms_output.put_line('New quantity is '|| new_quantity);
END;
问候
安迪