2016-12-07 68 views
1

我们假设我有一个Oracle数据库,其中有一个名为RUN_LOG的表,用于记录作业何时执行。针对Oracle数据库批处理“UPDATE vs. INSERT”查询

该表具有一个主键JOB_NAME,它唯一标识已执行的作业,以及一个名为LAST_RUN_TIMESTAMP的列,该列反映作业上次执行的时间。

当作业开始时,我想更新作业(如果存在)的现有行,或者向表中插入新行。

由于Oracle不支持REPLACE INTO式查询,因此有必要尝试使用UPDATE,如果零行受到影响,请使用INSERT

这通常是用类似下面的JDBC实现:

PreparedStatement updateStatement = connection.prepareStatement("UPDATE ..."); 
PreparedStatement insertStatement = connection.prepareStatement("INSERT ..."); 

updateStatement.setString(1, "JobName"); 
updateStatement.setTimestamp(2, timestamp); 

// If there are no rows to update, it must be a new job... 
if (updateStatement.executeUpdate() == 0) { 
    // Follow-up 
    insertStatement.setString(1, "JobName"); 
    insertStatement.setTimestamp(2, timestamp); 
    insertStatement.executeUpdate(); 
} 

这是一个相当良好走过的道路,我很舒服的这种做法。


然而,让我们假设我用例需要我插入了非常大量的这些记录。对数据库执行单独的SQL查询将会太“太琐碎”。相反,我想开始分批这些INSERT/UPDATE查询

鉴于UPDATE查询的执行将被推迟,直到该批承诺,我不能看到多少行受到了影响,直到稍后的日期。

实现这种REPLACE INTO类似结果的最佳机制是什么?

我宁愿避免使用存储过程,因为我宁愿将持久性逻辑保留在这个地方(类),而不是在Java代码和数据库之间分发它。

+0

对不起,但我不明白:那么MERGE呢? – hinotf

回答

5

什么是SQL MERGE语句。您可以将大量记录插入临时表,然后将临时表与RUN_LOG合并。例如:

merge into RUN_LOG tgt using (
    select job_name, timestamp 
    from my_new_temp_table 
) src 
on (src.job_name = tgt.job_name) 
when matched then update set 
    tgt.timestamp = src.timestamp 
when not matched then insert values (src.job_name, src.timestamp) 
; 
+0

我完全不知道MERGE的说法,谢谢! – jwa

+1

我建议明确列举'INSERT'部分中的列名:'insert(tgt.job_name,tgt.timestamp)values(src.job_name,src.timestamp)'。否则,在添加/删除列或者(更糟糕)列设备的排序在设备和生产之间不同时,您可能会遇到令人讨厌的意外。 –