2012-11-20 226 views
7

我有一張表,其中包含商店ID和玩家ID以及玩家的積分。 我想要做的是將一個商店轉移到另一個商店,事情是商店id和玩家id形成一個獨特的索引。我想要做的是重複鍵更新,而不是讓它失敗,將一個條目的點添加到另一個條目並刪除「from」條目。 喜歡的東西:更新重複密鑰更新

UPDATE `playerspoints` 
SET `boardId`=$to 
WHERE `boardId`=$from 
ON DUPLICATE KEY UPDATE `points`=.... get the idea? 
+0

我的猜測是,2(ish)查詢和if/else塊會更簡單。你有沒有想要這樣做的特殊原因? – landons

+2

充分利用語言的潛力是一種很好的做法。它更多的是發現事物,並以更快的方式做事。 –

+0

如果將它部署到生產中,我真的希望這有[正確的SQL轉義](http://bobby-tables.com/)。看到像這樣的裸體變數令人擔憂。 – tadman

回答

3

你只能改變一個衝突行中ON DUPLICATE KEY區域的上下文。此外,據我所知,這是INSERT聲明的一個屬性。

您需要的是一個簡單的總賬,您可以記錄餘額的加減,然後將其手動或使用觸發器列表。

例如,最簡單的方法是:

INSERT INTO points_adjustments (boardId_from, boardId_to, points) 
    VALUES (?, ?, ?) 

這可能更容易表現爲一對條目:

INSERT INTO points_adjustments (boardId, points) 
    VALUES (?, ?) 

你會添加一個條目+ n個點,並一個匹配的-n。您隨時可以使用SUM(points)獲得餘額。您可以將其包裝在VIEW中以使檢索更容易,或者如果需要,可以使用觸發器將這些總和非規格化爲另一個表的列。

一個簡單的觸發器會發出爲每個受影響boardId下面的語句:

INSERT INTO balances (boardId, points) VALUES (?, ?) 
    ON DUPLICATE KEY SET points=points+VALUES(points) 

這樣就避免了在首位鍵衝突,並提供發生的交易的審計記錄。

在任何情況下,要自動完成所有這些,您可能必須使用觸發器。

+0

我喜歡這個解決方案,但我從來沒有使用觸發器,我猜這是我的時間。 至於逃避... $ from \t =(int)mysql_real_escape_string($ _ REQUEST ['from']); \t \t \t \t $ to \t =(int)mysql_real_escape_string($ _ REQUEST ['to']); \t \t \t \t $ delete = $ condition [mysql_real_escape_string($ _ REQUEST ['delete'])]; \t \t \t \t $ contest = $ condition [mysql_real_escape_string($ _ REQUEST ['contest'])]; 還有什麼我可以做的嗎? –

+0

是的。觸發器將是合乎邏輯的下一步。自動刪除約束違規是一個雄心勃勃的想法:) – landons

+0

是......使用PDO(或其他數據庫抽象庫)。 – landons

0

不可以。在MySQL中違反約束條件時不能刪除記錄。你可能會做一個更新前的觸發器來檢查即將發生的約束衝突,但即使如此(從5.1開始),你也無法修改同一個表的數據(無論如何,這可能會導致無限循環)。

在塔德曼的回答之前只完成了一半。我個人喜歡他的想法。