【问题标题】:Using Oracle MERGE on same table based on condition根据条件在同一张表上使用 Oracle MERGE
【发布时间】:2017-10-07 06:09:49
【问题描述】:

我已经创建了如下的 Oracle 序列:

CREATE SEQUENCE TASK_ID_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;  

我有一个数据库表TASK,如下:

TASK_ID nextval from TASK_ID_SEQ
TASK_DATE   SYSDATE
TASK_TYPE   <value fed from data>

如果TASK_TYPE 还没有出现在TASK 表中,我需要插入一条新的TASK 记录,以表示TASK_DATE 中的日期,否则忽略它。

下面的语法正确吗?

MERGE INTO TASK a
USING (SELECT b.task_date FROM TASK b) 
ON (a.task_type = b.task_type)
WHEN NOT MATCHED THEN
[INSERT INTO TASK]

或者应该是这样的:

MERGE INTO TASK a
USING (SELECT b.task_date FROM TASK b) 
ON (a.task_type = b.task_type)
WHEN MATCHED THEN
[]
WHEN MATCHED THEN
[INSERT INTO TASK]

我可以交替使用

MERGE INTO TASK USING (select 1 from DUAL) . . .

请提出建议。

【问题讨论】:

  • 如果它只是一个插入,那么为什么不使用 select 使用插入语句呢?
  • @user75ponic 有两个原因,一个是为了适应未来的更新,而且改动很小,第二个是你预计 Merge 会比 insert 慢吗?如果没有,那为什么不呢?

标签: sql oracle oracle11g upsert sql-merge


【解决方案1】:

您的业务规则表明 DATE 和 TYPE 匹配。所以你的代码有两个问题:

  1. USING 子句需要选择确定匹配所需的所有条件。
  2. ON 子句需要测试确定匹配所需的所有标准。

此外,如果您不需要更新现有记录,则可以省略 WHEN MATCHED 分支。所以你的 MERGE 语句应该是这样的:

merge into task 
using ( 
    select date '2017-05-08' as dt, 'BATTLE' as typ from dual union all
    select date '2017-05-08' as dt, 'JUGGLE' as typ from dual union all
    select date '2017-05-08' as dt, 'PLOT' as typ from dual ) q
on (task.task_date = q.dt
    and task.task_type = q.typ)
when not matched then 
    insert values (task_id_seq.nextval, q.dt, q.typ)
/   

演示。鉴于这个起点...

SQL> select * from task;

   TASK_ID TASK_DATE  TASK_TYPE
---------- ---------- ----------
         1 2017-05-06 CLEAN
         2 2017-05-06 BATTLE
         3 2017-05-06 JUGGLE
         4 2017-05-07 JUGGLE
         5 2017-05-07 CLEAN
         6 2017-05-07 NAP
         7 2017-05-08 BATTLE

7 rows selected.
SQL>

... 上面的 MERGE 应该插入两行(数据源中的一行与现有行匹配)。

SQL> merge into task 
  2  using ( 
  3     select date '2017-05-08' as dt, 'BATTLE' as typ from dual union all
  4     select date '2017-05-08' as dt, 'JUGGLE' as typ from dual union all
  5     select date '2017-05-08' as dt, 'PLOT' as typ from dual ) q
  6  on (task.task_date = q.dt
  7     and task.task_type = q.typ)
  8  when not matched then 
  9     insert values (task_id_seq.nextval, q.dt, q.typ)
 10  /  

2 rows merged.

SQL> select * from task
  2  /

   TASK_ID TASK_DATE  TASK_TYPE
---------- ---------- ----------
         1 2017-05-06 CLEAN
         2 2017-05-06 BATTLE
         3 2017-05-06 JUGGLE
         4 2017-05-07 JUGGLE
         5 2017-05-07 CLEAN
         6 2017-05-07 NAP
         7 2017-05-08 BATTLE
         9 2017-05-08 JUGGLE
        10 2017-05-08 PLOT

9 rows selected.

SQL> 

数据来源并不完全清楚。所以在上面的例子中,我使用 DUAL 生成了一组任务。如果您想要从昨天的集合中为今天创建一组新的任务,则 USING 子句将如下所示:

merge into task 
using ( 
    select trunc(sysdate) as dt, task_type as typ 
    from task
    where task_date = trunc(sysdate) - 1 ) q
on (task.task_date = q.dt
    and task.task_type = q.typ)
when not matched then 
    insert values (task_id_seq.nextval, q.dt, q.typ)
/

使用与此版本之前相同的起始数据插入三行:

SQL> select * from task;

   TASK_ID TASK_DATE  TASK_TYPE
---------- ---------- ----------
         1 2017-05-06 CLEAN
         2 2017-05-06 BATTLE
         3 2017-05-06 JUGGLE
         4 2017-05-07 JUGGLE
         5 2017-05-07 CLEAN
         6 2017-05-07 NAP
         7 2017-05-08 BATTLE
        11 2017-05-08 CLEAN
        12 2017-05-08 JUGGLE
        13 2017-05-08 NAP

10 rows selected.

SQL> 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多