在ORACLE DB中执行upsert并且不起作用

时间:2015-03-26 07:35:03

标签: php sql oracle

我在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 Call,

$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);
            }

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

2 个答案:

答案 0 :(得分:2)

首先,我建议在这种情况下使用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真的相同。

答案 1 :(得分:1)

当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