2010-06-09 132 views
2

這是我的第一篇文章!忍受着我。 我有一個更新聲明,我想了解SQL Server如何處理它。更新表設置字段

UPDATE a 
    SET a.vField3 = b.vField3 
FROM tableName a 
    INNER JOIN tableName b on a.vField1 = b.vField1 
     AND b.nField2 = a.nField2 – 1 

這是我的查詢以其最簡單的形式。

vField1 is a Varchar 
nField2 is an int (autonumber) 
vField3 is a Varchar 

我已經離開了WHERE子句,所以明白了邏輯,否則會使得這個nessessity。

說vField1是客戶編號,客戶有3個記錄 nField2中的值是1,2和3連續。 vField3是一個狀態

當更新來a.nField2 = 1沒有a.nField2 -1所以它繼續 當更新來a.nField2 = 2,b.nField2 = 1 當更新到a.nField2 = 3,b.nField2 = 2

因此,當更新是在a.nField2 = 2上,別名b反映了先前行上的內容(b.nField2 = 1) 而且它SET a.vField3的Varchar值= b.vField3

當更新位於a.nField2 = 3時,別名b反映了先前行上的內容(b.nField2 = 2) 而且它(應該)設置a.vField3 = b.vField3的Varchar值

當過程完成時 - 三條記錄中的第二條記錄與預期相符 - 第二條記錄的vField3中的值反映第一條記錄中vField3的值

但是,第三條記錄的vField3並不反映第二條記錄中vField3的值。

我認爲這表明SQL Server可能正在生成某種事務然後進行更新。

問題:如何在每次事務後獲得數據庫更新,以便我可以引用每個事務生成的值?

謝謝。 davlyo

+0

「但是,第三條記錄的vField3不反映第二條記錄中vField3的值。」你得到了什麼?你是指第二個記錄的新值或原始值? – mdma 2010-06-09 21:58:34

+0

你從完全錯誤的角度出發,根據遊標而不是邏輯集合操作來思考 - 閱讀一本書並挖掘其中的差異,但不用擔心,對於第一個處理SQL的程序員來說,這是一個非常常見的缺陷時間。 – Cruachan 2010-06-09 22:23:15

+0

我認爲「tablename a」和「tablename b」實際上是2個不同的表,而不是一個具有兩個不同別名的表? (這會使它成爲一個自連接,而且毫無意義) – BradC 2010-06-09 22:28:23

回答

1

整個更新查詢是一個操作 - 如果這是事務中唯一的事務,則爲一個事務。所以,查詢沒有看到它自己的結果。該查詢沒有任何隱含的順序 - 幾乎就像它一次發生一樣。

還要記住,這是一個自加入,所以最初的第二個/第三個記錄不會在查詢運行後。一個記錄將被「丟失」 - 原始的第三個記錄,並且價值1的記錄重複。

E.g.你開始,客戶,aField2,aField3

mdma 1  A 
mdma 2  B 
mdma 3  C 

運行你的更新後,值將

mdma 1 A 
mdma 2 A 
mdma 3 B 

這就是你看到/期待?

3

首先,最重要的是,您誤以爲您的記錄是「連續」保存的,因此事務將在邏輯上實現某種定義的循環。事實上,您的數據庫中的記錄的順序是undefined,並且在所有以這種有序的方式考慮您的表存儲是沒有意義的。事實上,你應該儘量徹底擺脫它,否則它會導致你陷入各種陷阱和壞習慣。相反,試着從邏輯上考慮按照設置(數學意義上)操作執行的語句,而不是光標遍歷。

當然,在大多數關係數據庫中,沒有ORDER BY子句的SELECT檢索記錄的順序是按照插入順序,但這是一個實現問題,實際上絕不應該依賴於任何邏輯(如果您關心訂單,總是使用ORDER BY子句檢索數據)。爲了強調,根據ANSI SQL,沒有ORDER BY子句的情況下,從數據庫檢索記錄的順序是未定義的 - 從技術上講,甚至不需要在同一個SELECT語句的順序執行上保持一致。

因此,爲了使關係數據庫上的UPDATE操作產生一致的結果,任何查詢必須作爲單個事務操作。該事務捕獲它將更新的記錄的快照,以一致的原子方式更新它們,然後將結果應用到數據。根本沒有邏輯上的SQL循環記錄或任何東西的概念。

+1

實際上,在大多數關係數據庫中,如果沒有指定ORDER BY,記錄將按照* clustered index *的順序檢索,所以即使實現細節不支持FIFO記錄排序的概念,除非你沒有聚集索引(壞主意),或者你總是以與聚簇索引相同的順序插入(只有當索引位於'IDENTITY'列上時才爲真)。 – Aaronaught 2010-06-10 01:23:22

+0

@Aarounaught是的,你是正確的,儘管當然在大多數數據庫上我使用大多數數據庫,聚集索引是一個標識列,所以它實際上是插入順序,但正如你指出的那樣,這也是一個神器。 – Cruachan 2010-06-10 08:50:26