[英]Oracle converting working SQL with CTE to procedure
I have some SQL code, which works as designed.我有一些 SQL 代码,可以按设计工作。 I'm trying to convert the code to a procedure to make it flexible so that different values maybe passed in.我正在尝试将代码转换为过程以使其灵活,以便可以传入不同的值。
I am running into an error while trying to create the procedure.我在尝试创建过程时遇到错误。
Errors: PROCEDURE CREATE_XXX
Line/Col: 28/1 PL/SQL: SQL Statement ignored
Line/Col: 37/3 PL/SQL: ORA-00928: missing SELECT keyword
The problem seems to be occurring in a CTE, which contains a SELECT so I'm a bit confused and can use some assistance.问题似乎出现在 CTE 中,其中包含一个 SELECT,所以我有点困惑,需要一些帮助。
Below is a test CASE that contains the working SQL along with the procedure I'm trying to create.下面是一个测试案例,其中包含工作 SQL 以及我尝试创建的过程。
Thanks in advance for your help, patience and expertise and to all who answer.提前感谢您的帮助、耐心和专业知识,并感谢所有回答的人。
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;
/
The issue is this statement.问题是这个声明。
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
);
I'm not sure what you're trying to accomplish.我不确定你想要完成什么。 Syntactically, if you want to have a CTE as part of an insert
, you'd want to do an insert... select
从句法上讲,如果您想将 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;
From there, though, you've still got several syntax issues that it's not obvious how you'd want to solve all of them.但是,从那里开始,您仍然遇到一些语法问题,您并不清楚您希望如何解决所有这些问题。
p.schedule_id
isn't valid because there is no schedule_id
column in the params
CTE. p.schedule_id
无效,因为params
CTE 中没有schedule_id
列。 My guess is that you want to alias i_schedule_id
to schedule_id
in the CTE.我的猜测是您想在 CTE i_schedule_id
别名为schedule_id
。l.location_id
doesn't make sense because you're not selecting from a table that could plausibly be given an alias of l
. l.location_id
没有意义,因为您不是从一个可能被赋予l
别名的表中进行选择。base_date
, start_date
, or end_date
column in your params
CTE. params
CTE 中没有base_date
、 start_date
或end_date
列。 And it's not obvious how you'd plausibly fix that.而且你如何合理地解决这个问题并不明显。 Maybe you actually intended the subsequent select
statement to actually be part of this insert
statement despite the fact that you terminated the insert
with a semicolon?也许您实际上希望后续的select
语句实际上成为此insert
语句的一部分,尽管您用分号终止了insert
? If so, maybe you want如果是这样,也许你想要
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;
That would produce code that compiles at least.这将产生至少可以编译的代码。 There doesn't, however, appear to be any reason to bother with a CTE here at all.但是,似乎根本没有任何理由为 CTE 而烦恼。 Just reference the local variables and input parameters directly.直接引用局部变量和输入参数即可。 I've also eliminated the order by
since it doesn't make sense in the context of an insert
statement.我还删除了order by
因为它在insert
语句的上下文中没有意义。 I assume there is a reason that you need to take input parameters as integers and convert them to local variables with the same name and a different data type rather than just passing in interval
parameters to the procedure.我假设有一个原因需要将输入参数作为整数并将它们转换为具有相同名称和不同数据类型的局部变量,而不是仅仅将interval
参数传递给过程。 If you can do that, you can further simplify things by eliminating the local variables.如果你能做到这一点,你就可以通过消除局部变量来进一步简化事情。
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.