2016-12-07 67 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)'。否則,在添加/刪除列或者(更糟糕)列設備的排序在設備和生產之間不同時,您可能會遇到令人討厭的意外。 –