接受PL / SQL函数中的uni或multi维参数

时间:2017-04-11 22:31:01

标签: oracle plsql

我正在尝试在PL / SQL中编写一个函数nbrJobs()来计算用户过去曾经拥有的作业数。

为了做到这一点,我首先需要确定“员工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包含多个元组。

所以,现在我对输入参数类型感到困惑。我应该使用VARRAY,嵌套TABLECURSOR,还有其他什么? 如果选择了多行,SELECT实际返回了什么?

2 个答案:

答案 0 :(得分: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语句。您无需更改函数以使其适用于多行。

现在,您将如何使用上面使用的SELECT语句在PL / SQL中执行此操作。您将需要使用游标循环结果,或者如果您只想将所有行的结果提取到变量中,则可以使用集合类型。

使用光标( 我在上面的例子中使用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语句,但现在在Cursor 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返回多行,因此我们需要告诉编译器我们确实期望这样做,以便编译器不会抛出更多行返回的错误。

最后但并非最不重要的是,鉴于您在上面的示例nbrJobsTotal中使用变量名称SELECT nbrJobs(first_name, last_name) INTO nbrJobsTotal FROM employees,我认为您真正想要尝试做的是总结所有不同的数量员工在贵公司工作的工作。你可以做到这一点,但使用内置的SUM()函数,它是一个聚合函数,即它只返回一行没有GOUP BY子句:

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

答案 1 :(得分:1)

您可以使用Table of Type - 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