2017-04-11 26 views
0

我正在嘗試在PL/SQL中編寫一個函數nbrJobs()來統計用戶過去的作業數。接受PL/SQL函數中的單維或多維參數

爲了做到這一點,我首先需要確定一個「員工ID」,可以通過一對(名字,姓氏)來確定。

我設法做到這一點時,函數的參數是:

nbrJobs(firstName IN VARCHAR2(20), lastName IN VARCHAR2(25)) 

然後,這個簡單的測試,沒有任何問題上運行:

DECLARE 
    nbrJobsTotal NUMBER; 
BEGIN 
    SELECT nbrJobs(first_name, last_name) INTO nbrJobsTotal 
    FROM employees 
    WHERE employee_id = 101 
END 

現在的問題是,我的工作,應也可以使用那種呼叫:

SELECT nbrJobs(first_name, last_name) INTO nbrJobsTotal FROM employees 

與表employees co擁有多個元組。

所以,現在我對輸入參數類型感到困惑..我應該使用VARRAY,嵌套TABLECURSOR,別的? 如果選擇多行,SELECT實際上會返回什麼內容?

回答

3

針對SELECT語句的每一行執行PL/SQL函數。因此,如果您在常規的SELECT SQL語句中調用您的函數,您將獲得每條記錄的值。

這裏是通過連接第一和最後一個名字聯繫在一起的例子:

CREATE OR REPLACE FUNCTION NAME (p_FIRST_NAME IN VARCHAR2, p_LAST_NAME IN VARCHAR2) 
    RETURN VARCHAR2 
AS 
BEGIN 
    RETURN p_FIRST_NAME || ' ' || p_LAST_NAME; 
END; 
/

SELECT first_name, last_name, name(first_name, last_name) FROM HR.employees; 

FIRST_NAME LAST_NAME NAME(FIRST_NAME,LAST_NAME) 
---------- --------- -------------------------- 
Ellen  Abel  Ellen Abel 
Sundar  Ande  Sundar Ande 
Mozhe  Atkinson Mozhe Atkinson 
David  Austin  David Austin 

正如你所看到的,用於執行PL/SQL函數每一行並連接的姓氏和名字,然後返回結果作爲SELECT聲明的新列。您不需要更改該功能以使其適用於多行。

現在,您將如何在PL/SQL中使用上面用作示例的SELECT語句執行此操作。您將不得不使用遊標來循環結果,或者如果您只想將所有行的結果提取到變量中,則可以使用集合類型。

使用光標( 我在我的例子證明這上面使用Cursor FOR LOOP):

BEGIN 
    FOR result IN (SELECT first_name, last_name, name(first_name, last_name) name FROM HR.employees) LOOP 
     DBMS_OUTPUT.PUT_LINE(result.first_name || ', ' || result.last_name || ', ' || result.name); 
    END LOOP; 
END; 
/

Ellen, Abel, Ellen Abel 
Sundar, Ande, Sundar Ande 
Mozhe, Atkinson, Mozhe Atkinson 
David, Austin, David Austin 

這裏發生的是,我在執行同樣的SELECT語句,但現在裏面光標FOR LOOP允許我循環返回的每一行。在這種情況下,我只是將結果輸出到控制檯中。

如果你只想保存所有的行到一個變量,你必須使用一個PL/SQL Collection

DECLARE 
    -- Specify cursor with expected results 
    CURSOR c1 IS 
    SELECT first_name, last_name, name(first_name, last_name) name 
    FROM HR.employees; 

    -- Create PL/SQL type for a nested table of the rowtype of the cursor (first_name, last_name, name) 
    TYPE NameSet IS TABLE OF c1%ROWTYPE; 

    employees NameSet; -- Instantiate a variable of the nested table of records 

BEGIN 
    -- Assign values to nested table of records: 

    SELECT first_name, last_name, name(first_name, last_name) name 
    BULK COLLECT INTO employees 
    FROM HR.employees; 

    -- Print nested table of records: 

    FOR i IN employees.FIRST .. employees.LAST LOOP 
     DBMS_OUTPUT.PUT_LINE (
     employees(i).first_name || ' ' || 
     employees(i).last_name || ', ' || 
     employees(i).name 
    ); 
    END LOOP; 
END; 
/

Ellen Abel, Ellen Abel 
Sundar Ande, Sundar Ande 
Mozhe Atkinson, Mozhe Atkinson 
David Austin, David Austin 

正如你可以在這裏看到相同的SELECT執行,但在這裏我們使用BULK COLLECT INTO而不僅僅是INTO 。這是因爲SELECT返回多於一行,因此我們需要告訴編譯器,我們確實期望這樣做,以便編譯器不會拋出一個返回更多行的錯誤。

最後但並非最不重要的一點,考慮到在上面的示例SELECT nbrJobs(first_name, last_name) INTO nbrJobsTotal FROM employees中使用變量名nbrJobsTotal,我認爲您真正想在此做的是總結員工在您公司中的所有不同職位的數量。你可以做到這一點,但使用內置SUM()功能這是一個聚合函數,也就是說,它只會返回一個行沒有GOUP BY條款:

SELECT SUM(nbrJobs(first_name, last_name)) INTO nbrJobsTotal FROM employees 
+0

感謝你爲這個全面的答案。畢竟這很簡單! –

+0

@Xing你甚至在說什麼。我不是諷刺。 「畢竟這很簡單」意味着我嘗試了許多複雜的事情,完全失去了自我,而事實上我只是保持簡單,gvenzl幫助我理解了他的完整答案,因此「謝謝你」。 –

+1

沒有難過的感覺!我非常確定答案只是函數的SUM(),但我認爲不是給出一個單行的答案,而是增加一點關於PL/SQL函數如何工作的上下文。本着「給一個人一條魚,他可以吃一天,教他如何釣魚,他可以一輩子吃完」的精神。希望這個解釋不僅有助於@ArthurDeschamps,而且還將幫助許多其他人找到這個問題。至於其餘的問題,我很高興這個問題已經解決,並且(希望)已經學到了一些東西。 – gvenzl

1

您可以使用Table ofType - 以bulk collect返回的所有行由select聲明。

根據您例如,它應該是這樣的:

DECLARE 
    nbrJobsTotal NUMBER; 
    TYPE jobsTotalTable_type IS TABLE OF nbrJobsTotal%TYPE; 
    jobsTotalTable jobsTotalTable_type ; 
BEGIN 
    --bulk collect results 
    SELECT nbrJobs(first_name, last_name) BULK COLLECT INTO jobsTotalTable 
    FROM employees; 

    --print results 
    FOR indx IN 1 .. jobsTotalTable.COUNT LOOP 
    DBMS_OUTPUT.PUT_LINE(jobsTotalTable (indx)); 
    END LOOP; 
END