2017-04-11 79 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