Oracle 插入、选择和不存在
Posted
技术标签:
【中文标题】Oracle 插入、选择和不存在【英文标题】:Oracle INSERT, SELECT and NOT EXISTS 【发布时间】:2021-10-22 20:43:24 【问题描述】:我有一个程序,它运行良好。有时将相同的 VALUES 传递到过程中并生成唯一的 KEY 违规。
我知道这可以通过使用轻松解决 通常的解决方案 将错误记录到 子句,或使用 /*+ ignore_row_on_dupkey_index ... */
我看到了这个链接,并试图通过查看 VALUES 是否已经在 PRIMARY KEY 中来实施 @OMG Ponies NOT EXISTS 解决方案,但经过数小时的研究和尝试不同的方法我没有成功
Avoid duplicates in INSERT INTO SELECT query in SQL Server
我很好奇如何在我的情况下实施此解决方案。
提前感谢所有回复的人以及您的帮助、耐心和专业知识。
我的工作测试 CASE 在下面(未修改)在下面。顺便说一句,我在实时 SQL 中进行测试,以防有人想使用相同的环境。
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
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 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 'G'
END AS location_type
FROM dual
CONNECT BY level <= 15;
ALTER TABLE locations
ADD ( CONSTRAINT locations_pk
PRIMARY KEY (location_id));
CREATE OR REPLACE PROCEDURE CREATE_SCHEDULE
(
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;
/
EXEC CREATE_SCHEDULE(1,TRUNC(SYSDATE))
【问题讨论】:
【参考方案1】:使用MERGE
声明:
CREATE OR REPLACE PROCEDURE CREATE_SCHEDULE(
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') ;
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
) 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;
/
【讨论】:
以上是关于Oracle 插入、选择和不存在的主要内容,如果未能解决你的问题,请参考以下文章
oracle表中如果存在就不更新,如果不存在就插入的语句怎么写