【问题标题】:Oracle 12c: Can I invoke a function from a WITH clause which both takes and returns a table?Oracle 12c:我可以从 WITH 子句中调用一个函数,该函数既接受又返回一个表?
【发布时间】:2019-09-14 19:25:00
【问题描述】:

我想编写一个 PL/SQL 函数,该函数可用于各种查询,尤其是 WITH 子句的子查询。棘手的部分是我希望该函数同时 receivereturn 单列 TABLE(或 CURSOR)信息。

详细信息:假设这个函数只是根据一些非常复杂的标准对员工 ID 列表进行排序。我们会有这个:

  • 我的函数名为 SORT_EMPLOYEES
  • 我的函数将包含员工 ID (emp_id) 的 1 列表作为输入。
  • 此输入类型可能是 TABLE 类型 EMP_T_TYPE。
  • 此返回类型可能也是 TABLE 类型 EMP_T_TYPE。

到目前为止一切顺利,我希望。

现在,我认为我几乎可以在任何地方使用带有 TABLE 运算符的函数输出;例如:

    WITH
    wanted_emps AS (...),  -- find employees we want, as table of emp_id
    ranked_emps AS (
        SELECT rownum() as rank, emp_id 
        FROM TABLE(SORT_EMPLOYEES(...???...))
    ),
    ...

问题是:如何从 'wanted_emps' 获取员工列表并将其作为 SORT_EMPLOYEES 的输入?上面的“...???...”中有什么内容?这甚至可能吗?

请注意,我希望从普通 SQL 中使用它,尤其是从上面所示的 WITH 子句的子查询中使用它——而不是从 PL/SQL 中使用。谢谢!

【问题讨论】:

    标签: sql oracle function common-table-expression


    【解决方案1】:

    这是一个示例,说明如何将 COLLECT 值放入集合中,然后将其传递给返回另一个集合的 FUNCTION

    Oracle 设置

    CREATE TYPE numbers_table AS TABLE OF NUMBER;
    
    CREATE TABLE test_data ( grp, value ) AS
      SELECT 1, 1 FROM DUAL UNION ALL
      SELECT 1, 2 FROM DUAL UNION ALL
      SELECT 1, 3 FROM DUAL UNION ALL
      SELECT 2, 4 FROM DUAL UNION ALL
      SELECT 2, 5 FROM DUAL UNION ALL
      SELECT 3, 6 FROM DUAL;
    

    查询

    WITH FUNCTION square( i_numbers IN numbers_table ) RETURN numbers_table
    IS
      p_numbers numbers_table := numbers_table();
      p_count   PLS_INTEGER;
    BEGIN
      IF i_numbers IS NULL THEN
        p_count := 0;
      ELSE
        p_count := i_numbers.COUNT;
      END IF;
      p_numbers.EXTEND( p_count );
      FOR i IN 1 .. p_count LOOP
        p_numbers(i) := i_numbers(i) * i_numbers(i);
      END LOOP;
      RETURN p_numbers;
    END;
    collected_rows ( grp, grouped_values ) AS (
      SELECT grp,
             CAST(
               COLLECT( value ORDER BY value )
               AS numbers_table
             )
      FROM   test_data
      GROUP BY grp
    )
    SELECT c.grp,
           t.COLUMN_VALUE AS squared_value
    FROM   collected_rows c
           CROSS JOIN
           TABLE( square( c.grouped_values ) ) t;
    

    输出

    玻璃钢 | SQUARED_VALUE --: | ------------: 1 | 1 1 | 4 1 | 9 2 | 16 2 | 25 3 | 36

    db小提琴here

    【讨论】:

    • 非常感谢您的回复!这可以在 Oracle 12c 中工作吗? (数据库小提琴是 Oracle 18c)
    • 它应该在 12c 中工作。如果您使用 CREATE FUNCTION 而不是在 WITH 子查询因式分解子句中声明函数,它将在 11g (db<>fiddle) 中工作。
    猜你喜欢
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 2021-12-23
    • 1970-01-01
    • 2016-12-30
    • 2016-12-31
    • 2017-03-10
    • 1970-01-01
    相关资源
    最近更新 更多