Oracle 将 INSERT 转换为 MERGE ot not EXISTS

Oracle converting an INSERT to MERGE ot not EXISTS

我有以下代码,运行良好。如果我 运行 程序多次使用相同的值,我会得到 PRIMARY KEY violation,这是我期望的。是否可以将 INSERT 转换为 MERGE 或 NOT EXISTS 以避免此问题?

我在网上看到的示例似乎是使用文字值或带有 MERGE 的 ON 语句。

由于我是新手 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 table schedule_assignment(
       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)
  );

CREATE OR REPLACE PROCEDURE 
create_schedule_assignment (
  p_schedule_id IN NUMBER,
  p_start_date  IN DATE,
  p_end_date   IN DATE
)
IS
BEGIN
  INSERT INTO schedule_assignment(
  schedule_id,
   schedule_date
  )
  SELECT 
        p_schedule_id,
         COLUMN_VALUE
  FROM   TABLE(generate_dates_pipelined(p_start_date, p_end_date));
END;

EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');

将程序重写为

SQL> CREATE OR REPLACE PROCEDURE
  2  create_schedule_assignment (
  3    p_schedule_id IN NUMBER,
  4    p_start_date  IN DATE,
  5    p_end_date   IN DATE
  6  )
  7  IS
  8  BEGIN
  9    merge into schedule_assignment s
 10      using (select p_schedule_id as schedule_id,
 11                    column_value  as schedule_date
 12             from table(generate_dates_pipelined(p_start_date, p_end_date))
 13            ) x
 14      on (    x.schedule_id = s.schedule_id
 15          and x.schedule_date = s.schedule_date
 16         )
 17      when not matched then insert (schedule_id, schedule_date)
 18        values (x.schedule_id, x.schedule_date);
 19  END;
 20  /

Procedure created.

SQL>

测试:最初,table 为空:

SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
  2  from schedule_assignment group by schedule_id;

no rows selected

运行第一次的程序:

SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');

PL/SQL procedure successfully completed.

Table内容:

SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
  2  from schedule_assignment group by schedule_id;

SCHEDULE_ID MINDAT     MAXDATE      COUNT(*)
----------- ---------- ---------- ----------
          1 21/08/2021 30/08/2021         10

运行再次使用相同参数的程序:

SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');

PL/SQL procedure successfully completed.

SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');

PL/SQL procedure successfully completed.

SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');

PL/SQL procedure successfully completed.

结果:没有任何变化,table 中没有行(但也没有错误):

SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
  2  from schedule_assignment group by schedule_id;

SCHEDULE_ID MINDAT     MAXDATE      COUNT(*)
----------- ---------- ---------- ----------
          1 21/08/2021 30/08/2021         10

SQL>

运行程序相同SCHEDULE_ID,但日期不同:

SQL> EXEC create_schedule_assignment (1, DATE '2021-08-29', DATE '2021-09-02');

PL/SQL procedure successfully completed.

SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
  2  from schedule_assignment group by schedule_id;

SCHEDULE_ID MINDAT     MAXDATE      COUNT(*)
----------- ---------- ---------- ----------
          1 21/08/2021 02/09/2021         13

SQL>

对;行数现在增加到 13(之前是 10,因为添加了 31.08.、01.09. 和 02.09.)。

SCHEDULE_ID:

SQL> EXEC create_schedule_assignment (2, DATE '2021-09-05', DATE '2021-09-07');

PL/SQL procedure successfully completed.

SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
  2  from schedule_assignment group by schedule_id;

SCHEDULE_ID MINDAT     MAXDATE      COUNT(*)
----------- ---------- ---------- ----------
          1 21/08/2021 02/09/2021         13
          2 05/09/2021 07/09/2021          3

SQL>

我觉得不错。