【问题标题】:update table pl/sql更新表 pl/sql
【发布时间】:2015-10-01 20:23:29
【问题描述】:

我想使用 pl/sql 函数更新下表,问题是我设法编写了一个触发代码,但我想改用“函数”重写它。 我希望客户 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];

请指教

【问题讨论】:

  • 为什么?您的要求背后的目的是什么?
  • 更多函数知识
  • 所以这是一个学习函数的自知练习?首先,如果我是你,我会尝试编写这样的函数。您必须决定需要哪些输入和输出参数,然后考虑如何使用这些参数来查找、更新和返回相关值。如果您遇到困难或有其他问题,请尝试一下,并用您目前所掌握的内容更新您的问题。然后,我们可以为您提供更多有用的建议。
  • oracle 不支持函数中的DML 操作。
  • @jWeaver 如果从 SQL 语句(例如 selectinsert)调用函数,则为 true,除非函数声明为 pragma autonomous_transaction (尽管我不一定建议这样做)。在 PL/SQL 块中调用的函数可以执行 DML。

标签: sql oracle plsql


【解决方案1】:

所以我现在所做的是我从一个过程中调用一个函数(创建的过程,因为我无法打印所有三个值),我做了一些假设。

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;

问候
安迪

【讨论】:

    【解决方案2】:

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

    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);

    【讨论】:

    • 这不会返回以前的数量值,这似乎部分是 OP 想要的。尽管目前还不清楚基本要求是什么。 (在过程中提交通常也不是一个好主意,调用者应该这样做)。
    • 我不同意commit 部分。如果您有一个从多个位置调用的过程,那么您可以更好地在一个位置使用commit。如果您有一个大型数据库,并且您在调用过程的某处错过了提交,则很难找到问题。
    • 直到您有另一个程序进行其他更改,然后调用这个程序,然后自己做更多的工作,这会出错。如果这回滚,那么你已经失去了原子性,因为这个变化和它已经提交之前的任何东西,让你的数据处于奇怪的状态。调用过程可能并不期待它。我认为这将更难追踪。如果应用程序在最高级别控制提交/回滚,那么您就可以避免问题。 (It's not just me)
    【解决方案3】:

    您的程序没有使用您声明的参数;身体应该更像:

    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 和产品 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.
    

    【讨论】:

    • 非常感谢您的解决方案.. 如果我想使用 'function' 而不是 procedure ,可以将 procedure 单词替换为 function 并且所有其他行都一样吗?更多功能在这里tutorialspoint.com/plsql/plsql_functions.htm请指教
    • @Chaz - 不完全;一个函数返回一些东西,一个过程没有;因此,您将删除 OUT 参数并改为使用 return number。您还需要一个局部变量来选择旧值,并且您还需要返回该局部变量。但是这里的程序更合适。我仍然不确定你为什么想要一个函数。
    • 我需要一个函数用于工作目的..你能不能更新代码来代替过程..这将是一个巨大的帮助..谢谢你提前
    • @Chaz - 好的,我已经添加了一个函数版本,但我仍然建议使用过程方法。
    • 你可以在一个函数中有额外的 OUT 参数,但是当你可以只使用一个过程并且需要尽可能多的 out 参数时,你为什么要这样做呢?使用带有额外 OUT 参数的函数是不正常的做法,并且在将来维护它时会令人困惑。你一直说你需要使用一个函数——为什么?恕我直言,“工作目的”还不够。如果调用代码可以处理一个函数,它就可以很容易地处理一个过程!
    【解决方案4】:

    我从您的问题中了解到,每当在 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;
    

    对不起,如果我理解了它。

    问候 安迪

    【讨论】:

    • 谢谢,但我想要的是让用户能够输入客户 ID 并将数量更新为新值,并显示客户 ID 和旧数量值和新值的输出。你能更新代码以匹配我想要的吗?提前致谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多