Oracle INSERT 预计 SELECT
Oracle INSERT expecting SELECT
我有一个测试用例,它工作正常。
在这种情况下,有一段代码带有 COMMENT FAILED,我试图将这些行插入到 table 中,最终提示 ignore_row_on_dupkey_index.
在尝试 INSERT 时,我得到了预期 SELECT 的错误,我不明白为什么会有 SELECT。我显然遗漏了一些东西,但我无法弄清楚如何解决这个问题。
测试的设置有点冗长(我很抱歉)但是您可以剪切和粘贴设置的所有内容,因为除了失败评论开始的最后部分外,它都可以正常工作。
如果有人能告诉我为什么 INSERT 不起作用并提供修复,我们将不胜感激。预先感谢所有回复的人和您的专业知识。顺便说一句,如果你想模拟我的环境,我正在现场测试 SQL
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE OR REPLACE TYPE nt_date IS TABLE OF DATE;
/
CREATE OR REPLACE FUNCTION generate_dates_pipelined(
p_from IN DATE,
p_to IN DATE
)
RETURN nt_date PIPELINED DETERMINISTIC
IS
v_start DATE := TRUNC(LEAST(p_from, p_to));
v_end DATE := TRUNC(GREATEST(p_from, p_to));
BEGIN
LOOP
PIPE ROW (v_start);
EXIT WHEN v_start >= v_end;
v_start := v_start + INTERVAL '1' DAY;
END LOOP;
RETURN;
END generate_dates_pipelined;
/
CREATE OR REPLACE FUNCTION CONVERT_TO_SECONDS(
i_date_string IN VARCHAR2
)
RETURN INTEGER DETERMINISTIC
AS
BEGIN
RETURN ( TO_DATE(i_date_string, 'HH24:MI:SS')
- TO_DATE('00:00:00', 'HH24:MI:SS')
) * 86400;
END;
/
Create table employees(
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
card_num VARCHAR2(10),
work_days VARCHAR2(7)
);
INSERT INTO employees (
employee_id,
first_name,
last_name,
card_num,
work_days
)
WITH names AS (
SELECT 1, 'John', 'Doe', 'D564311','YYYYYNN' FROM dual UNION ALL
SELECT 2, 'Justin', 'Case', 'C224311','YYYYYNN' FROM dual UNION ALL
SELECT 3, 'Mike', 'Jones', 'J288811','YYYYYNN' FROM dual UNION ALL
SELECT 4, 'Jane', 'Smith', 'S564661','YYYYYNN' FROM dual
) SELECT * FROM names;
create table access_history(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
employee_id NUMBER(6),
card_num varchar2(10),
location_id number(4),
access_date date,
processed NUMBER(1) default 0
);
CREATE TABLE locations AS
SELECT level AS location_id,
'Door ' || level AS location_name,
CASE round(dbms_random.value(1,3))
WHEN 1 THEN 'G'
WHEN 2 THEN 'G'
WHEN 3 THEN 'G'
END AS location_type
FROM dual
CONNECT BY level <= 5;
ALTER TABLE locations
ADD ( CONSTRAINT locations_pk
PRIMARY KEY (location_id));
create table schedule_assignment(
seq_num NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
schedule_id number(4),
schedule_date DATE,
employee_id NUMBER(6) DEFAULT 0,
constraint sa_chk check (schedule_date=trunc(schedule_date, 'dd')),
constraint sa_pk primary key (schedule_id, schedule_date,employee_id));
CREATE OR REPLACE PROCEDURE create_schedule_assignment (
p_schedule_id IN NUMBER,
p_start_date IN DATE,
p_end_date IN DATE,
p_employee_id IN NUMBER DEFAULT 0
)
IS
BEGIN
merge into schedule_assignment s
using (select p_schedule_id as schedule_id,
p_employee_id as employee_id,
column_value as schedule_date
from table(generate_dates_pipelined(p_start_date, p_end_date))
) x
on ( x.schedule_id = s.schedule_id
and x.schedule_date = s.schedule_date
and
x.employee_id =
s.employee_id
)
when not matched then insert (schedule_id, schedule_date, employee_id)
values (x.schedule_id, x.schedule_date,
x.employee_id);
END;
/
create table schedule(
seq_num NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
schedule_id NUMBER(4),
location_id number(4),
base_date DATE,
start_date DATE,
end_date DATE,
constraint schedule_pk primary key (schedule_id, location_id, base_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)
);
CREATE OR REPLACE PROCEDURE CREATE_SCHEDULE(
i_schedule_id IN PLS_INTEGER,
-- i_base_date IN DATE,
p_start_date in date,
p_end_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;
i_base_date date;
BEGIN
l_offset := NUMTODSINTERVAL(i_offset, 'SECOND') ;
l_incr := NUMTODSINTERVAL(i_incr, 'MINUTE') ;
l_duration := NUMTODSINTERVAL(i_duration, 'MINUTE') ;
for i in ( select column_value each_date from TABLE(generate_dates_pipelined(p_start_date, p_end_date)) )
loop
i_base_date := i.each_date;
MERGE INTO schedule dst
USING (
SELECT i_schedule_id AS schedule_id,
l.location_id,
i_base_date AS 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
where location_id in (
select location_id
from locations
where location_type = 'G'
)
) src
ON ( src.schedule_id = dst.schedule_id
AND src.location_id = dst.location_id
AND src.base_date = dst.base_date
)
WHEN NOT MATCHED THEN
INSERT (
schedule_id,
location_id,
base_date,
start_date,
end_date
) VALUES (
src.schedule_id,
src.location_id,
src.base_date,
src.start_date,
src.end_date
);
end loop;
END;
/
CREATE OR REPLACE PROCEDURE CREATE_ACCESS_HISTORY_INTERVAL
(
i_start_date IN DATE,
i_end_date IN DATE,
i_interval IN PLS_INTEGER DEFAULT 10
) AS
BEGIN
INSERT INTO access_history (employee_id, card_num, location_id, access_date)
WITH date_rows ( start_date, end_date ) AS (
SELECT i_start_date,
i_end_date
FROM DUAL
UNION ALL
SELECT start_date +
NUMTODSINTERVAL(i_interval, 'MINUTE'),
end_date
FROM date_rows
WHERE start_date +
NUMTODSINTERVAL(i_interval, 'MINUTE') < end_date
)
SELECT e.employee_id
, e.card_num
, l.location_id
, d.start_date
FROM employees e
CROSS JOIN locations l
CROSS JOIN date_rows d;
END;
/
CREATE table schedule_history(
seq_num INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
schedule_id NUMBER(4),
base_date DATE,
employee_id NUMBER(6),
location_id NUMBER(4),
start_date DATE,
end_date DATE,
access_date DATE,
status VARCHAR2(1),
constraint schedule_history_pk primary key (schedule_id, start_date, end_date)
);
EXEC create_schedule_assignment(1,TRUNC(SYSDATE),TRUNC(SYSDATE)+2,1);
/
EXEC CREATE_ACCESS_HISTORY_INTERVAL(TRUNC(SYSDATE)+NUMTODSINTERVAL(CONVERT_TO_SECONDS('23:00:10'),'SECOND'),TRUNC(SYSDATE+1)+NUMTODSINTERVAL(CONVERT_TO_SECONDS('02:30:10'),'SECOND'))
EXEC CREATE_SCHEDULE(1,SYSDATE,SYSDATE+2,CONVERT_TO_SECONDS('23:00:00'));
/
WITH sch AS
(
SELECT s.schedule_id,
sa.schedule_date,
sa.employee_id,
s.location_id, s.start_date,
s.end_date
, ROW_NUMBER () OVER ( PARTITION BY s.schedule_id, s.location_id, TRUNC (s.start_date)
ORDER BY s.start_date
) AS rn
, TRUNC (s.start_date) AS this_day
, TRUNC (s.start_date) + 1 AS next_day
, s.start_date - INTERVAL '2' MINUTE AS early_date
,
s.end_date + INTERVAL '2' MINUTE AS late_date FROM schedule s
-- need JOIN to get employee_id
JOIN schedule_assignment sa
ON s.schedule_id = sa.schedule_id
AND TRUNC(s.start_date) = sa.schedule_date
), ah AS
(
SELECT a.employee_id, a.location_id, a.access_date
, ROW_NUMBER () OVER ( PARTITION BY a.employee_id, a.location_id, TRUNC (a.access_date)
ORDER BY a.access_date
) AS rn
FROM access_history a
)
select sch.schedule_id,
sch.schedule_date,
sch.employee_id,
sch.location_id, sch.start_date,
sch.end_date, ah.access_date,
CASE
WHEN ah.access_date < sch.early_date THEN 'E'
WHEN
ah.access_date >=
sch.early_date AND
ah.access_date <= sch.late_date THEN 'G'
WHEN ah.access_date > sch.late_date THEN 'L'
WHEN ah.access_date IS NULL THEN 'M'
END AS status
FROM sch
LEFT OUTER JOIN ah ON ah.employee_id = sch.employee_id
AND ah.location_id = sch.location_id
AND ah.access_date >= sch.this_day
AND ah.access_date < sch.next_day
ORDER BY
sch.employee_id, sch.start_date;
-- FAILED --
WITH sch AS
(
SELECT s.schedule_id,
sa.schedule_date,
sa.employee_id,
s.location_id, s.start_date,
s.end_date
, ROW_NUMBER () OVER ( PARTITION BY s.schedule_id, s.location_id, TRUNC (s.start_date)
ORDER BY s.start_date
) AS rn
, TRUNC (s.start_date) AS this_day
, TRUNC (s.start_date) + 1 AS next_day
, s.start_date - INTERVAL '2' MINUTE AS early_date
,
s.end_date + INTERVAL '2' MINUTE AS late_date FROM schedule s
-- need JOIN to get employee_id
JOIN schedule_assignment sa
ON s.schedule_id = sa.schedule_id
AND TRUNC(s.start_date) = sa.schedule_date
), ah AS
(
SELECT a.employee_id, a.location_id, a.access_date
, ROW_NUMBER () OVER ( PARTITION BY a.employee_id, a.location_id, TRUNC (a.access_date)
ORDER BY a.access_date
) AS rn
FROM access_history a
)
INSERT INTO SCHEDULE_HISTORY(
schedule_id
,base_date
,employee_id
,location_id
,start_date
,end_date
,access_date
,status
)
SELECT sch.schedule_id,
sch.schedule_date,
sch.employee_id,
sch.location_id, sch.start_date,
sch.end_date, ah.access_date,
CASE
WHEN ah.access_date < sch.early_date THEN 'E'
WHEN
ah.access_date >=
sch.early_date AND
ah.access_date <= sch.late_date THEN 'G'
WHEN ah.access_date > sch.late_date THEN 'L'
WHEN ah.access_date IS NULL THEN 'M'
END AS status
FROM sch
LEFT OUTER JOIN ah ON ah.employee_id = sch.employee_id
AND ah.location_id = sch.location_id
AND ah.access_date >= sch.this_day
AND ah.access_date < sch.next_day;
您的失败陈述可以概括为:
WITH sch AS
(
....
), ah AS
(
...
)
INSERT INTO SCHEDULE_HISTORY(
...
)
SELECT ...
FROM sch
LEFT OUTER JOIN ah ON ...
您插入的位置有误;它应该组织为:
INSERT INTO SCHEDULE_HISTORY(
...
)
WITH sch AS
(
....
), ah AS
(
...
)
SELECT ...
FROM sch
LEFT OUTER JOIN ah ON ...
... 将 CTE 作为 select 的一部分,在插入之后,而不是在插入之前。这就是您对之前的 INSERT INTO employees
语句所做的。
解析器期望 select
在 with
子句之后;因此出现了您看到的错误。
db<>fiddle,尽管它仍然因数据的唯一约束错误而失败。您可以在仅查询版本中看到重复项 - 因此您需要修复该查询。
我有一个测试用例,它工作正常。
在这种情况下,有一段代码带有 COMMENT FAILED,我试图将这些行插入到 table 中,最终提示 ignore_row_on_dupkey_index.
在尝试 INSERT 时,我得到了预期 SELECT 的错误,我不明白为什么会有 SELECT。我显然遗漏了一些东西,但我无法弄清楚如何解决这个问题。
测试的设置有点冗长(我很抱歉)但是您可以剪切和粘贴设置的所有内容,因为除了失败评论开始的最后部分外,它都可以正常工作。
如果有人能告诉我为什么 INSERT 不起作用并提供修复,我们将不胜感激。预先感谢所有回复的人和您的专业知识。顺便说一句,如果你想模拟我的环境,我正在现场测试 SQL
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE OR REPLACE TYPE nt_date IS TABLE OF DATE;
/
CREATE OR REPLACE FUNCTION generate_dates_pipelined(
p_from IN DATE,
p_to IN DATE
)
RETURN nt_date PIPELINED DETERMINISTIC
IS
v_start DATE := TRUNC(LEAST(p_from, p_to));
v_end DATE := TRUNC(GREATEST(p_from, p_to));
BEGIN
LOOP
PIPE ROW (v_start);
EXIT WHEN v_start >= v_end;
v_start := v_start + INTERVAL '1' DAY;
END LOOP;
RETURN;
END generate_dates_pipelined;
/
CREATE OR REPLACE FUNCTION CONVERT_TO_SECONDS(
i_date_string IN VARCHAR2
)
RETURN INTEGER DETERMINISTIC
AS
BEGIN
RETURN ( TO_DATE(i_date_string, 'HH24:MI:SS')
- TO_DATE('00:00:00', 'HH24:MI:SS')
) * 86400;
END;
/
Create table employees(
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
card_num VARCHAR2(10),
work_days VARCHAR2(7)
);
INSERT INTO employees (
employee_id,
first_name,
last_name,
card_num,
work_days
)
WITH names AS (
SELECT 1, 'John', 'Doe', 'D564311','YYYYYNN' FROM dual UNION ALL
SELECT 2, 'Justin', 'Case', 'C224311','YYYYYNN' FROM dual UNION ALL
SELECT 3, 'Mike', 'Jones', 'J288811','YYYYYNN' FROM dual UNION ALL
SELECT 4, 'Jane', 'Smith', 'S564661','YYYYYNN' FROM dual
) SELECT * FROM names;
create table access_history(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
employee_id NUMBER(6),
card_num varchar2(10),
location_id number(4),
access_date date,
processed NUMBER(1) default 0
);
CREATE TABLE locations AS
SELECT level AS location_id,
'Door ' || level AS location_name,
CASE round(dbms_random.value(1,3))
WHEN 1 THEN 'G'
WHEN 2 THEN 'G'
WHEN 3 THEN 'G'
END AS location_type
FROM dual
CONNECT BY level <= 5;
ALTER TABLE locations
ADD ( CONSTRAINT locations_pk
PRIMARY KEY (location_id));
create table schedule_assignment(
seq_num NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
schedule_id number(4),
schedule_date DATE,
employee_id NUMBER(6) DEFAULT 0,
constraint sa_chk check (schedule_date=trunc(schedule_date, 'dd')),
constraint sa_pk primary key (schedule_id, schedule_date,employee_id));
CREATE OR REPLACE PROCEDURE create_schedule_assignment (
p_schedule_id IN NUMBER,
p_start_date IN DATE,
p_end_date IN DATE,
p_employee_id IN NUMBER DEFAULT 0
)
IS
BEGIN
merge into schedule_assignment s
using (select p_schedule_id as schedule_id,
p_employee_id as employee_id,
column_value as schedule_date
from table(generate_dates_pipelined(p_start_date, p_end_date))
) x
on ( x.schedule_id = s.schedule_id
and x.schedule_date = s.schedule_date
and
x.employee_id =
s.employee_id
)
when not matched then insert (schedule_id, schedule_date, employee_id)
values (x.schedule_id, x.schedule_date,
x.employee_id);
END;
/
create table schedule(
seq_num NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
schedule_id NUMBER(4),
location_id number(4),
base_date DATE,
start_date DATE,
end_date DATE,
constraint schedule_pk primary key (schedule_id, location_id, base_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)
);
CREATE OR REPLACE PROCEDURE CREATE_SCHEDULE(
i_schedule_id IN PLS_INTEGER,
-- i_base_date IN DATE,
p_start_date in date,
p_end_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;
i_base_date date;
BEGIN
l_offset := NUMTODSINTERVAL(i_offset, 'SECOND') ;
l_incr := NUMTODSINTERVAL(i_incr, 'MINUTE') ;
l_duration := NUMTODSINTERVAL(i_duration, 'MINUTE') ;
for i in ( select column_value each_date from TABLE(generate_dates_pipelined(p_start_date, p_end_date)) )
loop
i_base_date := i.each_date;
MERGE INTO schedule dst
USING (
SELECT i_schedule_id AS schedule_id,
l.location_id,
i_base_date AS 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
where location_id in (
select location_id
from locations
where location_type = 'G'
)
) src
ON ( src.schedule_id = dst.schedule_id
AND src.location_id = dst.location_id
AND src.base_date = dst.base_date
)
WHEN NOT MATCHED THEN
INSERT (
schedule_id,
location_id,
base_date,
start_date,
end_date
) VALUES (
src.schedule_id,
src.location_id,
src.base_date,
src.start_date,
src.end_date
);
end loop;
END;
/
CREATE OR REPLACE PROCEDURE CREATE_ACCESS_HISTORY_INTERVAL
(
i_start_date IN DATE,
i_end_date IN DATE,
i_interval IN PLS_INTEGER DEFAULT 10
) AS
BEGIN
INSERT INTO access_history (employee_id, card_num, location_id, access_date)
WITH date_rows ( start_date, end_date ) AS (
SELECT i_start_date,
i_end_date
FROM DUAL
UNION ALL
SELECT start_date +
NUMTODSINTERVAL(i_interval, 'MINUTE'),
end_date
FROM date_rows
WHERE start_date +
NUMTODSINTERVAL(i_interval, 'MINUTE') < end_date
)
SELECT e.employee_id
, e.card_num
, l.location_id
, d.start_date
FROM employees e
CROSS JOIN locations l
CROSS JOIN date_rows d;
END;
/
CREATE table schedule_history(
seq_num INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
schedule_id NUMBER(4),
base_date DATE,
employee_id NUMBER(6),
location_id NUMBER(4),
start_date DATE,
end_date DATE,
access_date DATE,
status VARCHAR2(1),
constraint schedule_history_pk primary key (schedule_id, start_date, end_date)
);
EXEC create_schedule_assignment(1,TRUNC(SYSDATE),TRUNC(SYSDATE)+2,1);
/
EXEC CREATE_ACCESS_HISTORY_INTERVAL(TRUNC(SYSDATE)+NUMTODSINTERVAL(CONVERT_TO_SECONDS('23:00:10'),'SECOND'),TRUNC(SYSDATE+1)+NUMTODSINTERVAL(CONVERT_TO_SECONDS('02:30:10'),'SECOND'))
EXEC CREATE_SCHEDULE(1,SYSDATE,SYSDATE+2,CONVERT_TO_SECONDS('23:00:00'));
/
WITH sch AS
(
SELECT s.schedule_id,
sa.schedule_date,
sa.employee_id,
s.location_id, s.start_date,
s.end_date
, ROW_NUMBER () OVER ( PARTITION BY s.schedule_id, s.location_id, TRUNC (s.start_date)
ORDER BY s.start_date
) AS rn
, TRUNC (s.start_date) AS this_day
, TRUNC (s.start_date) + 1 AS next_day
, s.start_date - INTERVAL '2' MINUTE AS early_date
,
s.end_date + INTERVAL '2' MINUTE AS late_date FROM schedule s
-- need JOIN to get employee_id
JOIN schedule_assignment sa
ON s.schedule_id = sa.schedule_id
AND TRUNC(s.start_date) = sa.schedule_date
), ah AS
(
SELECT a.employee_id, a.location_id, a.access_date
, ROW_NUMBER () OVER ( PARTITION BY a.employee_id, a.location_id, TRUNC (a.access_date)
ORDER BY a.access_date
) AS rn
FROM access_history a
)
select sch.schedule_id,
sch.schedule_date,
sch.employee_id,
sch.location_id, sch.start_date,
sch.end_date, ah.access_date,
CASE
WHEN ah.access_date < sch.early_date THEN 'E'
WHEN
ah.access_date >=
sch.early_date AND
ah.access_date <= sch.late_date THEN 'G'
WHEN ah.access_date > sch.late_date THEN 'L'
WHEN ah.access_date IS NULL THEN 'M'
END AS status
FROM sch
LEFT OUTER JOIN ah ON ah.employee_id = sch.employee_id
AND ah.location_id = sch.location_id
AND ah.access_date >= sch.this_day
AND ah.access_date < sch.next_day
ORDER BY
sch.employee_id, sch.start_date;
-- FAILED --
WITH sch AS
(
SELECT s.schedule_id,
sa.schedule_date,
sa.employee_id,
s.location_id, s.start_date,
s.end_date
, ROW_NUMBER () OVER ( PARTITION BY s.schedule_id, s.location_id, TRUNC (s.start_date)
ORDER BY s.start_date
) AS rn
, TRUNC (s.start_date) AS this_day
, TRUNC (s.start_date) + 1 AS next_day
, s.start_date - INTERVAL '2' MINUTE AS early_date
,
s.end_date + INTERVAL '2' MINUTE AS late_date FROM schedule s
-- need JOIN to get employee_id
JOIN schedule_assignment sa
ON s.schedule_id = sa.schedule_id
AND TRUNC(s.start_date) = sa.schedule_date
), ah AS
(
SELECT a.employee_id, a.location_id, a.access_date
, ROW_NUMBER () OVER ( PARTITION BY a.employee_id, a.location_id, TRUNC (a.access_date)
ORDER BY a.access_date
) AS rn
FROM access_history a
)
INSERT INTO SCHEDULE_HISTORY(
schedule_id
,base_date
,employee_id
,location_id
,start_date
,end_date
,access_date
,status
)
SELECT sch.schedule_id,
sch.schedule_date,
sch.employee_id,
sch.location_id, sch.start_date,
sch.end_date, ah.access_date,
CASE
WHEN ah.access_date < sch.early_date THEN 'E'
WHEN
ah.access_date >=
sch.early_date AND
ah.access_date <= sch.late_date THEN 'G'
WHEN ah.access_date > sch.late_date THEN 'L'
WHEN ah.access_date IS NULL THEN 'M'
END AS status
FROM sch
LEFT OUTER JOIN ah ON ah.employee_id = sch.employee_id
AND ah.location_id = sch.location_id
AND ah.access_date >= sch.this_day
AND ah.access_date < sch.next_day;
您的失败陈述可以概括为:
WITH sch AS
(
....
), ah AS
(
...
)
INSERT INTO SCHEDULE_HISTORY(
...
)
SELECT ...
FROM sch
LEFT OUTER JOIN ah ON ...
您插入的位置有误;它应该组织为:
INSERT INTO SCHEDULE_HISTORY(
...
)
WITH sch AS
(
....
), ah AS
(
...
)
SELECT ...
FROM sch
LEFT OUTER JOIN ah ON ...
... 将 CTE 作为 select 的一部分,在插入之后,而不是在插入之前。这就是您对之前的 INSERT INTO employees
语句所做的。
解析器期望 select
在 with
子句之后;因此出现了您看到的错误。
db<>fiddle,尽管它仍然因数据的唯一约束错误而失败。您可以在仅查询版本中看到重复项 - 因此您需要修复该查询。