更新表pl / sql

时间:2015-07-13 14:06:23

标签: sql oracle plsql

我想使用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];

请咨询

3 个答案:

答案 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;

问候
安迪