2015-07-13 65 views
-1

我想用pl/sql函数更新下面的表格,事情是我设法写了一个触发器代码,但我想用'function'来代替它。 我想为顾客5从30增加其以200和使用户能够输入:更新表格pl/sql

1)CUSTOMER_ID和 2)200为更新的量的数字5。 并在更新之前和之后打印出客户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]; 

请指教

+1

为什么?你的要求背后的目的是什么? – Boneist

+0

更多功能知识 – Chaz

+2

所以这是一个自学知识练习来了解功能?首先,如果我是你,我会尝试写这样的功能。您必须决定您需要的输入和输出参数,然后考虑如何使用参数来查找,更新和返回相关值。尝试一下,如果您遇到困难或有其他问题,请使用目前为止的内容更新您的问题。然后,我们可以给你更有帮助的指针。 – Boneist

回答

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. 
+0

非常感谢你的解决方案..如果我想使用“函数”而不是程序,是否可以用函数替换程序字,而所有其他行将是相同的?更多关于功能在这里http://www.tutorialspoint.com/plsql/plsql_functions.htm 请咨询 – Chaz

+0

@Chaz - 不完全;一个函数返回一些东西,一个程序不会;所以你可以删除OUT参数并使用“返回号码”。您还需要一个局部变量来选择旧值,并且您还要返回该局部变量。但是一个程序在这里更合适。我仍然不确定为什么你需要这个功能。 –

+0

我需要一个函数在这里工作的目的..你可以请更新代码的功能,而不是程序..这将是一个巨大的青睐..谢谢advace – Chaz

0

我已经从你的问题理解是要自动更新客户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; 

很抱歉,如果我的理解它,否则。

问候 安迪

+0

谢谢,但我想要的是让用户输入一个客户ID和更新数量到一个新的价值,并显示客户ID和旧的数量值和新的价值的输出。你能否更新代码来匹配我想要的?在此先感谢 – Chaz

0

要更新,你可以使用例如表:

CREATE OR REPLACE PROCEDURE Updatesales( 
    xCustomer_ID IN Table1.custumerId%TYPE, 
     xProduct_ID IN Table1.productId%TYPE, 
    xQuantity IN Table1.quantity%TYPE) 
AS 
BEGIN 
     UPDATE sales 
    SET  quantity = xQuantity 
    WHERE customer_id = xCustomer_ID; 

     COMMIT; 
END; 
/

要调用这个过程中,您使用:
Updatesales(4, 25, 100);

+0

这不会返回以前的数量值,这似乎部分是OP想要的。虽然很不清楚底层要求是什么。 (在一个过程中提交也不是一个好主意,调用者应该这样做)。 –

+0

我不同意'提交'部分。如果您有一个从多个位置调用的过程,那么您可以在一个地方更好地使用'commit'。如果你有一个大的数据库,并且你在某个调用某个过程的某个地方错过了一个提交,那么很难找到这个问题。 – Tenzin

+0

直到您有其他过程发生其他更改,然后调用此过程,然后执行更多自己的工作,从而发生错误。如果这个回滚,那么你已经失去了原子性,因为这个改变以及它已经被提交之前的任何东西,使得你的数据处于一个奇怪的状态。调用过程可能不会期待它。我认为这将很难追查。如果应用程序控制最高级别的提交/回滚,则可以避免该问题。 ([这不只是我](https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1519405621318#9903839346165)) –

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; 

问候
安迪