如何通过pl sql函数从表中生成列表?

Posted

技术标签:

【中文标题】如何通过pl sql函数从表中生成列表?【英文标题】:how to generate a liste from a table by plsql function? 【发布时间】:2019-12-03 15:24:23 【问题描述】:

我需要创建一个函数来通过选择查询从表中生成列表。首先,我创建了一个包和函数来生成一个表,但我得到了错误。

CREATE OR REPLACE PACKAGE test AS
    TYPE date_record IS RECORD(
       list_target VARCHAR2(50));
    TYPE date_table IS TABLE OF date_record;
    FUNCTION get_ups(partition_date_in VARCHAR2)
        RETURN date_table
        PIPELINED;
END;


CREATE OR REPLACE PACKAGE BODY test AS
    FUNCTION get_ups(partition_date_in VARCHAR2)
        RETURN date_table
        PIPELINED IS
        rec            date_record;
    BEGIN
        SELECT ltrim(TO_CHAR(MONTH,'mm-yyyy'),'0') BULK COLLECT AS rec
            FROM 
                (
                select add_months (trunc (to_date('09/01/2019','dd/mm/yyyy'), 'MM'), 1*Level -1)
                Month   FROM Dual
                CONNECT BY Level <= MONTHS_BETWEEN(to_date('09/01/2019','dd/mm/yyyy'), to_date('09/02/2019','dd/mm/yyyy')) + 1
                order by MONTH
                );
        -- you would usually have a cursor and a loop here   
        PIPE ROW (rec);
        RETURN;
    END get_ups;
END;

当我跑步时

SELECT *  FROM table(test.get_ups('09/01/2019'));

Errore SQL [4063] [72000]: ORA-04063: package body "SYS.TEST" contiene errori

您能帮忙解决这个问题并生成一个列表吗?

【问题讨论】:

package body "SYS.TEST" 为了将来参考,请不要将 SYS 模式用于您自己的对象。它是 Oracle 维护的模式,对数据库的完整性至关重要。将其用于您自己的目的可能会破坏您的数据库(在现实生活中,它会使您的 Oracle 支持合同无效)。使用 SYS 创建用户帐户并授予其权限,然后使用该架构构建您的程序。 运行 select * from user_errors; 以查看哪些编译错误会影响该包。 【参考方案1】:

您正在处理日期,但还想传递和检索字符串;你为什么要这么做?

如果我明白你想要做什么,那就是将日期参数传递给函数并获取日期列表。由于您从未在代码中使用过该参数,因此我假设您希望获取日期(作为参数传递)和 sysdate 之间的日期。

你会这样做。

当您想从 SQL 中使用它时,您必须在该级别创建类型:

SQL> create or replace type t_my_row is object (val date);
  2  /

Type created.

SQL> create or replace type t_my_tab is table of t_my_row;
  2  /

Type created.

SQL>

包装规格和正文:

SQL> create or replace package test as
  2        function get_ups(par_date in date) return t_my_tab;
  3  end;
  4  /

Package created.

SQL> create or replace package body test as
  2    function get_ups (par_date in date)
  3      return t_my_tab
  4    is
  5      l_tab   t_my_tab := t_my_tab();
  6    begin
  7      select t_my_row(add_months (trunc(par_date, 'MM'), Level - 1)) month
  8        bulk collect into l_tab
  9        from dual
 10       connect by level <= abs(months_between(par_date, sysdate) + 1);
 11
 12      return l_tab;
 13    end get_ups;
 14  end test;
 15  /

Package body created.

SQL>

测试:函数返回 DATES。应用TO_CHAR 函数以根据需要对其进行格式化,例如MM-YY

SQL> select to_char(val, 'mm-yy') result
  2    from table(test.get_ups(date '2019-01-09'));

RESULT
------
01-19
02-19
03-19
04-19
05-19
06-19
07-19
08-19
09-19

9 rows selected.

SQL>

如果这是你想要的,那很好。如果没有,请调整函数,以便它计算出你想要的,现在你已经大致了解了。


附:哦,是的:你得到的错误(用你的代码)说BULK COLLECT需要INTO(不是AS)。

但是,即使你修复它,你会得到的下一个错误将是

不能在 INTO 列表中混合使用单行和多行 (BULK)

等等。如果您有足够的耐心,您可能会走到最后并最终编译包体。如果没有,请查看我的代码。

【讨论】:

感谢您的互动。目标是生成日期列表 MM-YYYY [1-19,2-19,...],但在这之间我需要创建一个日期表。顺便说一句,我运行你的代码,我得到了 Errore SQL [904] [42000]: ORA-00904: "GET_UPS": identificativo non valido 不客气。我为误导你而道歉,这不是我的意图......首先我创建了一个独立的函数,然后是一个包,并且 - 在发布测试结果时 - 调用了错误的函数。再次抱歉。 无论如何:我修复了我的代码,您应该能够毫无问题地运行它。 “then”和“now”之间的区别在于类型是在 SQL 级别创建的,而不是在包规范中。其余的大致相同。【参考方案2】:

我不知道您的代码的用途,但如果您将其更改为:

CREATE OR REPLACE PACKAGE BODY tst AS
    FUNCTION get_ups(partition_date_in VARCHAR2)
        RETURN date_table
        PIPELINED IS
        rec            date_record;
    BEGIN
        for cur in (
        SELECT ltrim(TO_CHAR(MONTH,'mm-yyyy'),'0')  r
            FROM 
                (
                select add_months (trunc (to_date('09/01/2019','dd/mm/yyyy'), 'MM'), 1*Level -1)
                Month   FROM Dual
                CONNECT BY Level <= MONTHS_BETWEEN(to_date('09/01/2019','dd/mm/yyyy'), to_date('09/02/2019','dd/mm/yyyy')) + 1
                order by MONTH
                ))
        loop
            PIPE row(date_record(cur.r));
        end loop;
    END get_ups;
END;
/

它会起作用的。

【讨论】:

很遗憾,没有,我收到此错误“Errore SQL [900] [42000]: ORA-00900: istruzione SQL non valida” 为什么在循环中将 date_record 作为函数调用?这不是函数

以上是关于如何通过pl sql函数从表中生成列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在访问报告中生成列表?

在 Oracle PL/SQL 中生成字母数字序列

循环,从数组中生成带有函数的按钮

如何在选择语句的“NOT IN”子句中使用逗号分隔的字符串列表作为 pl/sql 存储的函数参数

在没有映射函数的列表中生成排列

将 XML 输出放回表中的函数