2015-07-13 36 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; 

問候
安迪