使用WITH STATEMENT在Oracle中创建日历函数

pu82cl6c  于 2022-11-22  发布在  Oracle
关注(0)|答案(2)|浏览(115)

我来自SQL Server,有时我不熟悉Oracle语法,我想创建一个函数,将日期和日期数作为参数,并创建一个表函数。
我的原始查询是:

VAR TREND = 1;
VAR OBS_DATE = 20221109;
VAR N_DAYS = 21;

WITH CAL AS
(
    SELECT
        TO_DATE(:OBS_DATE, 'YYYYMMDD') + (LEVEL - 1 * :TREND) DT, ROW_NUMBER() OVER(ORDER BY NULL) - 1 IX
    FROM 
        DUAL
    WHERE 
        TO_CHAR(TO_DATE(:OBS_DATE, 'YYYYMMDD') + (LEVEL - 1 * :TREND) , 'D') NOT IN (1,7)
    CONNECT BY LEVEL <= :N_DAYS + :N_DAYS/5*2+1
)
SELECT DT 
FROM CAL 
WHERE IX <= :N_DAYS;

但是当我尝试转换为函数时,它给我发送了一个错误,我不知道正确的语法是什么。
我的尝试是:

CREATE OR REPLACE FUNCTION FUN_BUS_CALENDAR(
    OBS_DATE IN DATE := SYSDATE
    , NDAYS IN NUMBER
    , TREND IN NUMBER
    )
    RETURN OBS_DATE DATE;
    BEGIN

    WITH CAL AS(
        SELECT
            TO_DATE(:OBS_DATE, 'YYYYMMDD') + (LEVEL - 1 * :TREND) OBS_DATE, ROW_NUMBER() OVER(ORDER BY NULL) - 1 IX
        FROM DUAL
        WHERE TO_CHAR(TO_DATE(:OBS_DATE, 'YYYYMMDD') + (LEVEL - 1 * :TREND) , 'D') NOT IN (1,7)
        CONNECT BY LEVEL <= :N_DAYS + :N_DAYS/5.*2.+1.
    )
    SELECT OBS_DATE FROM CAL WHERE IX <= :N_DAYS
        RETURN OBS_DATE
    END 
/
zujrkrfu

zujrkrfu1#

您可能应该只使用初始查询。
但是,如果确实需要函数,则可以使用管道函数:

CREATE FUNCTION BARRRAF.FUN_BUS_CALENDAR(
    OBS_DATE IN DATE := SYSDATE,
    NDAYS    IN NUMBER,
    TREND IN NUMBER
) RETURN SYS.ODCIDATELIST PIPELINED
IS
BEGIN
  FOR i IN 1 .. ndays LOOP
    PIPE ROW( obs_date + i - trend );
  END LOOP;
END;
/

如果你想生成一个行号,那么就使用子查询:

SELECT column_value AS obs_date,
       ROWNUM - 1 AS rn
FROM   TABLE(BARRRAF.FUN_BUS_CALENDAR(ndays => 3, trend=>1))

输出:
| 组织分解结构日期|注册号码|
| - -|- -|
| 2022年11月17日23时40分22秒|第0页|
| 2022年11月18日23时40分22秒|一个|
| 2022年11月19日23时40分22秒|2个|
fiddle

dvtswwa3

dvtswwa32#

下面是一个通用函数,可用于为以下INTERVAL秒、分钟、小时或天创建日历。
你可以把它传递给任何你喜欢的开始和结束日期/时间。较低或较高的日期可以在任何位置,因为有逻辑来弄清楚哪个是最少/最大的命令

CREATE OR REPLACE FUNCTION generate_dates(i_from_dat IN TIMESTAMP, i_to_dat IN TIMESTAMP, i_interval IN NUMBER, i_interval_type IN VARCHAR2)
RETURN VARCHAR2
SQL_MACRO
IS
BEGIN
    RETURN q'~SELECT LEAST(i_from_dat,i_to_dat) + NUMTODSINTERVAL( (LEVEL-1)*i_interval, i_interval_type ) AS dt
    FROM DUAL
    CONNECT BY LEAST(i_from_dat,i_to_dat)  + NUMTODSINTERVAL( (LEVEL-1)*i_interval, i_interval_type) < GREATEST(i_from_dat, i_to_dat)~';
END ;

SELECT * FROM generate_dates(
TIMESTAMP '2022-11-03 09:47:31',
TIMESTAMP '2022-11-03 12:37:11',
 30, 'MINUTE') ;

DT
03-NOV-22 09.47.31.000000 AM
03-NOV-22 10.17.31.000000 AM
03-NOV-22 10.47.31.000000 AM
03-NOV-22 11.17.31.000000 AM
03-NOV-22 11.47.31.000000 AM
03-NOV-22 12.17.31.000000 PM

SELECT * FROM generate_dates(
TIMESTAMP '2022-11-03 00:00:00',
TIMESTAMP '2022-11-08 00:00:00',
 1, 'DAY') ;

DT
03-NOV-22 12.00.00.000000 AM
04-NOV-22 12.00.00.000000 AM
05-NOV-22 12.00.00.000000 AM
06-NOV-22 12.00.00.000000 AM
07-NOV-22 12.00.00.000000 AM

相关问题