繁体   English   中英

Oracle 将使用 CTE 的工作 SQL 转换为程序

[英]Oracle converting working SQL with CTE to procedure

我有一些 SQL 代码,可以按设计工作。 我正在尝试将代码转换为过程以使其灵活,以便可以传入不同的值。

我在尝试创建过程时遇到错误。

Errors: PROCEDURE CREATE_XXX
Line/Col: 28/1 PL/SQL: SQL Statement ignored
Line/Col: 37/3 PL/SQL: ORA-00928: missing SELECT keyword

问题似乎出现在 CTE 中,其中包含一个 SELECT,所以我有点困惑,需要一些帮助。

下面是一个测试案例,其中包含工作 SQL 以及我尝试创建的过程。

提前感谢您的帮助、耐心和专业知识,并感谢所有回答的人。


ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';

create table schedule(
       schedule_id NUMBER(4),
       location_id number(4),
       base_date DATE,
       start_date DATE,
       end_date DATE,
         CONSTRAINT start_min check (start_date=trunc(start_date,'MI')),   
       CONSTRAINT end_min check (end_date=trunc(end_date,'MI')),
 CONSTRAINT end_gt_start CHECK (end_date >= start_date),
CONSTRAINT same_day CHECK (TRUNC(end_date) = TRUNC(start_date))
      );
/

    CREATE TABLE locations AS
    SELECT level AS location_id,
       'Door ' || level AS location_name,

    CASE round(dbms_random.value(1,3)) 
            WHEN 1 THEN 'A' 
            WHEN 2 THEN 'T' 
            WHEN 3 THEN 'T' 
         END AS location_type

    FROM   dual
    CONNECT BY level <= 15;


     ALTER TABLE locations 
         ADD ( CONSTRAINT locations_pk
       PRIMARY KEY (location_id));


-- works fine

WITH  params  AS
(
    SELECT  1 AS schedule_id,

TO_DATE ( '2021-08-21 00:00:00'
            , 'YYYY-MM-DD HH24:MI:SS'
            )             AS base_date
    ,    INTERVAL '83760' SECOND          AS offset
    ,    INTERVAL '10' MINUTE           AS incr
    ,    INTERVAL '5' MINUTE         AS duration
    FROM    dual
)
SELECT   p.schedule_id
,               l.location_id
,      p.base_date
,      p.base_date + offset
              + (incr * (ROWNUM - 1)) AS start_date
,      p.base_date + offset
              + (incr * (ROWNUM - 1))
            + p.duration         AS end_date
FROM      locations l
CROSS JOIN params   p
ORDER BY  start_date
;

-- having problem 

CREATE OR REPLACE PROCEDURE CREATE_XXX
 (
  i_schedule_id IN PLS_INTEGER,
  i_base_date IN DATE,
  i_offset IN PLS_INTEGER DEFAULT 0, 
i_incr IN PLS_INTEGER DEFAULT 10,
  i_duration         IN PLS_INTEGER DEFAULT 5
)
 AS 
 
l_offset  interval day to second;
   l_incr interval day to second;
  l_duration interval day to second;


BEGIN
 
l_offset :=
NUMTODSINTERVAL(i_offset, 'SECOND') ;

l_incr :=
NUMTODSINTERVAL(i_incr, 'MINUTE') ;

l_duration :=
NUMTODSINTERVAL(i_duration, 'MINUTE') ;


WITH params AS(
SELECT 
   i_schedule_id 
  ,i_base_date
  ,l_offset
  ,l_incr
  ,l_duration
FROM DUAL
)

INSERT INTO schedule(
        schedule_id
      ,location_id
      ,base_date
      ,start_date
      ,end_date
  )
  VALUES 
  (p.schedule_id 
   ,l.location_id 
   ,p.base_date
   ,start_date 
   ,end_date 
);

SELECT   p.schedule_id
,               l.location_id
,      p.base_date
,      p.base_date + p.offset
              + (p.incr * (ROWNUM - 1)) AS start_date
,      p.base_date + p.offset
              + (p.incr * (ROWNUM - 1))
            + p.duration         AS end_date
FROM      locations l
CROSS JOIN params   p
ORDER BY  start_date;
END;
/

问题是这个声明。

WITH params AS(
SELECT 
   i_schedule_id 
  ,i_base_date
  ,l_offset
  ,l_incr
  ,l_duration
FROM DUAL
)

INSERT INTO schedule(
        schedule_id
      ,location_id
      ,base_date
      ,start_date
      ,end_date
  )
  VALUES 
  (p.schedule_id 
   ,l.location_id 
   ,p.base_date
   ,start_date 
   ,end_date 
);

我不确定你想要完成什么。 从句法上讲,如果您想将 CTE 作为insert的一部分,则需要insert... select

INSERT INTO schedule(
        schedule_id
      ,location_id
      ,base_date
      ,start_date
      ,end_date
  )
WITH params AS(
SELECT 
   i_schedule_id 
  ,i_base_date
  ,l_offset
  ,l_incr
  ,l_duration
FROM DUAL
)
SELECT 
    p.schedule_id 
   ,l.location_id 
   ,p.base_date
   ,start_date 
   ,end_date 
  FROM params p;

但是,从那里开始,您仍然遇到一些语法问题,您并不清楚您希望如何解决所有这些问题。

  • p.schedule_id无效,因为params CTE 中没有schedule_id列。 我的猜测是您想在 CTE i_schedule_id别名为schedule_id
  • l.location_id没有意义,因为您不是从一个可能被赋予l别名的表中进行选择。
  • params CTE 中没有base_datestart_dateend_date列。 而且你如何合理地解决这个问题并不明显。

也许您实际上希望后续的select语句实际上成为此insert语句的一部分,尽管您用分号终止了insert 如果是这样,也许你想要

    INSERT INTO schedule(
            schedule_id
          ,location_id
          ,base_date
          ,start_date
          ,end_date
      )
    WITH params AS(
    SELECT 
       i_schedule_id schedule_id
      ,i_base_date base_date
      ,l_offset offset
      ,l_incr incr
      ,l_duration duration
    FROM DUAL
    )
SELECT   p.schedule_id
,               l.location_id
,      p.base_date
,      p.base_date + p.offset
              + (p.incr * (ROWNUM - 1)) AS start_date
,      p.base_date + p.offset
              + (p.incr * (ROWNUM - 1))
            + p.duration         AS end_date
FROM      locations l
CROSS JOIN params   p
ORDER BY  start_date;

这将产生至少可以编译的代码。 但是,似乎根本没有任何理由为 CTE 而烦恼。 直接引用局部变量和输入参数即可。 我还删除了order by因为它在insert语句的上下文中没有意义。 我假设有一个原因需要将输入参数作为整数并将它们转换为具有相同名称和不同数据类型的局部变量,而不是仅仅将interval参数传递给过程。 如果你能做到这一点,你就可以通过消除局部变量来进一步简化事情。

CREATE OR REPLACE PROCEDURE CREATE_XXX
 (
  i_schedule_id IN PLS_INTEGER,
  i_base_date IN DATE,
  i_offset IN PLS_INTEGER DEFAULT 0, 
i_incr IN PLS_INTEGER DEFAULT 10,
  i_duration         IN PLS_INTEGER DEFAULT 5
)
 AS 
 
l_offset  interval day to second;
   l_incr interval day to second;
  l_duration interval day to second;


BEGIN
 
l_offset :=
NUMTODSINTERVAL(i_offset, 'SECOND') ;

l_incr :=
NUMTODSINTERVAL(i_incr, 'MINUTE') ;

l_duration :=
NUMTODSINTERVAL(i_duration, 'MINUTE') ;


        INSERT INTO schedule(
                schedule_id
              ,location_id
              ,base_date
              ,start_date
              ,end_date
          )
    SELECT   i_schedule_id
    ,        l.location_id
    ,        i_base_date
    ,      i_base_date + l_offset
                  + (l_incr * (ROWNUM - 1)) AS start_date
    ,      i_base_date + l_offset
                  + (l_incr * (ROWNUM - 1))
                + l_duration         AS end_date
    FROM      locations l;
END;
/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM