【问题标题】:Doing upsert in ORACLE DB and doesnt work在 ORACLE DB 中做 upsert 并且不起作用
【发布时间】:2015-03-26 07:35:02
【问题描述】:

我在 oracle 中做了一个插入条件,当基于作业和子作业的记录不存在时,它应该插入,否则它应该更新其余的值。

这是我的程序,

CREATE OR REPLACE PROCEDURE WELTESADMIN.SP_JOB_INS
(
    JOB_V VARCHAR2,
    SUBJOB_V VARCHAR2,
    STARTDATE_V DATE,
    ENDDATE_V DATE,
    JOBWEIGHT_V NUMBER
)
AS BEGIN INSERT INTO PROJECT_SPAN (JOB, SUBJOB, STARTDATE, ENDDATE, WEIGHT) VALUES (JOB_V, SUBJOB_V, STARTDATE_V, ENDDATE_V, JOBWEIGHT_V);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
UPDATE PROJECT_SPAN SET STARTDATE = STARTDATE_V, ENDDATE = ENDDATE_V, WEIGHT = JOBWEIGHT_V WHERE JOB = JOB_V AND SUBJOB = SUBJOB_V;
END;
/

这是来自 PHP 调用,

$insertJobSpanSql = "BEGIN SP_JOB_INS(:JOB, :SUBJOB, :SDATE, :EDATE, :WT); END;";
            $insertJobSpanParse = oci_parse($conn, $insertJobSpanSql);
            oci_bind_by_name($insertJobSpanParse, ":JOB", $jobValue);
            oci_bind_by_name($insertJobSpanParse, ":SUBJOB", $subJobValue);
            oci_bind_by_name($insertJobSpanParse, ":SDATE", $startDateValue);
            oci_bind_by_name($insertJobSpanParse, ":EDATE", $endDateValue);
            oci_bind_by_name($insertJobSpanParse, ":WT", $jobWeightValue);
            $insertJobSpanRes = oci_execute($insertJobSpanParse);

            if ($insertJobSpanRes){
                oci_commit($conn);
            } else {
                oci_rollback($conn);
            }

问题是它不断插入具有相同作业和子作业值的新行。它应该是对新值的更新。

【问题讨论】:

  • 请显示您的索引的 DDL。此外,什么必须是独一无二的:一对(工作、子工作)还是其中之一?
  • 只有子作业是唯一的......

标签: php sql oracle


【解决方案1】:

首先,我建议在这种情况下使用MERGE

CREATE OR REPLACE PROCEDURE WELTESADMIN.SP_JOB_INS
(
    JOB_V VARCHAR2,
    SUBJOB_V VARCHAR2,
    STARTDATE_V DATE,
    ENDDATE_V DATE,
    JOBWEIGHT_V NUMBER
) AS 
BEGIN 
  merge into PROJECT_SPAN ps
  using (select JOB_V, SUBJOB_V, STARTDATE_V, ENDDATE_V, JOBWEIGHT_V 
           from dual) new_val
     on (ps.SUBJOB = new_val.SUBJOB_V and ps.JOB = new_val.JOB_V)
   when matched then update
    set STARTDATE = new_val.STARTDATE_V, 
        ENDDATE = new_val.ENDDATE_V, 
        WEIGHT = new_val.JOBWEIGHT_V
   when not matched then insert (JOB, SUBJOB, STARTDATE, ENDDATE, WEIGHT)
 values (new_val.JOB_V, new_val.SUBJOB_V, new_val.STARTDATE_V, 
         new_val.ENDDATE_V, new_val.JOBWEIGHT_V );
END;
/

如果它仍然没有更新值,请使用包DBMS_OUTPUT 或登录到表中以确保新旧JOBSUBJOB 确实相同。

【讨论】:

    【解决方案2】:

    当 DDL 语句违反主键或唯一键约束时,Oracle 会引发 DUP_VAL_ON_INDEX。因此,要使您的代码正常工作,您需要在 (job, subjob) 上定义一个主键,或者在该对上构建一个唯一索引。

    Oracle 以 MERGE 语句的形式提供了一种更简单的方法来实现 upsert:

    CREATE OR REPLACE PROCEDURE WELTESADMIN.SP_JOB_INS
    (
        JOB_V VARCHAR2,
        SUBJOB_V VARCHAR2,
        STARTDATE_V DATE,
        ENDDATE_V DATE,
        JOBWEIGHT_V NUMBER
    )
    AS BEGIN 
        merge into project_span ps
            using ( select job_v, subjob_v, startdate_v, enddate_v, jobweight_v from dual ) q
            on (ps.job = q.job_v
                and ps.subjob = q.subjob_v)
        when not matched then 
            insert (job, subjob, startdate, enddate, weight) 
            values (q.job_v, q.subjob_v, q.startdate_v, q.enddate_v, q.jobweight_v);
        when matched then
            update 
            set startdate = q.startdate_v
                , enddate = q.enddate_v
                , weight = q.jobweight_v 
               ;
    END;
    

    MERGE 语句在文档中。 Find out more.

    【讨论】:

      猜你喜欢
      • 2017-08-23
      • 2017-03-20
      • 1970-01-01
      • 2017-04-21
      • 2012-09-17
      • 1970-01-01
      • 2020-08-13
      • 1970-01-01
      • 2015-11-18
      相关资源
      最近更新 更多