2016-10-05 66 views
0

我看到很多人都問upserting(thisthisthisthisthisthismore甚至official doc)。插入到MySQL,但多列和唯一索引作爲重複檢查?

然而,新手不能很好地理解的東西是如何使用主鍵或唯一索引創建重複鍵。

我需要什麼
如果table1獨特的3列(attributeId, entityId, carId)的組合在table2副本,然後更新value列。否則取table1的行並將其插入table2

attributeId, entityId, carId組合對每一行都是唯一的。
ie:如果一行有1,2,5列,那麼沒有其他行會有1,2,5。但另一行可能有5,1,23,4,2

這裏的困境是關於創建唯一索引。難道不足以就去做這樣的:

CREATE INDEX PIndex ON table1 (attributeId, entityId, carId);

或者是有必要刪除所有其他指標,然後創建這個索引,然後運行這樣的查詢? (以下僞代碼):

INSERT INTO table1 (attributeId, entityId, carId, value, name) 
    VALUES (table2.attributeId,table2.entityId,table2.carId,table2.value,table2.name) 
ON DUPLICATE KEY UPDATE value=VALUES(value); 

的基本邏輯的存在:
如果在table2一個行中,有一個相應行中table1與恰好爲屬性Id,ENTITYID和carId相同的值,然後更新value列的table1,其中value列的值爲table2。如果沒有相應的行,則取行table2並將其附加到table1

回答

1

似乎規範是針對兩種不同的操作:1)更新table1中的現有行,以及2)將新行插入到table2中。

的規範說「更新值列」 ......我們認爲這意味着更新的table1該行的值列。

該規範還「插入到... table2

混淆,本說明書中還示出了示例性僞碼INSERT INTO table1


要執行的一個UPDATE table1基於值table2,假設我們要忽略那些具有在任何三列的NULL值的行...

UPDATE table1 t 
    JOIN table2 s 
    ON t.attributeid = s.attributeid 
    AND t.entityid = s.entityid 
    AND t.carid  = s.carid 
    SET t.value = s.value 

如果table2有「重複」(即在table2與三個屬性Id,ENTITYID和carid的相同的值的多個行,它是不定其中那些行的value將從服用。


要插入在表2中,但是從表1(再次假設這三個欄可能無法在表2是唯一的)「失蹤」行,我們可以用一個反連接模式以消除已經有行表1中的「匹配」。

例如:

INSERT INTO table1 (attributeid, entityid, carid, value) 
SELECT v.* 
    FROM (SELECT s.attribute_id 
       , s.entity_id 
       , s.carid 
       , s.value 
      FROM table2 s 
      LEFT 
      JOIN table1 r 
       ON r.attributeid = s.attributeid 
      AND r.entityid = s.entityid 
      AND r.carid  = s.carid 
      WHERE r.attributeid IS NULL 
      AND s.attributeid IS NOT NULL 
      AND s.entityid IS NOT NULL 
      AND s.carid  IS NOT NULL 
      GROUP 
       BY s.attributeid 
       , s.entityid 
       , s.carid 
     ) v 

如果有「重複」在表2(即,在表2的多個行與三個屬性Id,ENTITYID和carid的相同的值,它是不確定哪一行value將取自

如果在其他列或列組合上定義了其他UNIQUE約束,則該語句有可能拋出「重複鍵」錯誤(不知道鍵的定義,我們有點兒飛盲。)我們可以添加IGNORE關鍵字如果我們希望語句成功,只是忽略由於「唯一鍵」違規而無法插入的行。)

同樣,如果在table2與在三列相同的值(沒有給出指示該列的這種組合是在表2是唯一的)的行,它是不確定的,其這些行的value將被帶走。

可以在相反的方向執行相同的操作,交換查詢中所有出現的表格引用table1table2


沒有必要爲任何一個表添加一個UNIQUE KEY來執行這些操作。如果定義了合適的索引,那麼(可能)會帶來性能上的好處,這三列將作爲索引中的第一列。 (對於此操作,這不一定需要是UNIQUE索引。)

如果該列組合應該是唯一的,那麼通過所有方法在該組合列上添加一個UNIQUE KEY。但是指定的操作可以在沒有定義唯一鍵的情況下執行。

MySQL INSERT ... ON DUPLICATE KEY語法確實需要至少一個PRIMARY KEY或UNIQUE KEY來操作。如果目標表上存在多個UNIQUE KEY約束,並且INSERT會違反兩個或更多個唯一鍵約束,那麼我相信不確定哪些鍵將用於UPDATE操作。就我個人而言,我傾向於避免在定義了多個UNIQUE KEY的表上使用該語法。

+0

我的天啊。我很驚訝這是一個如此複雜的操作。完美的作品!非常感謝您花時間幫忙,spencer :) – Nav

0

您可以使用語法

ALTER IGNORE TABLE table1 ADD UNIQUE INDEX PIndex (attributeId, entityId, carId); 

根據the documentation

如果忽視的是指定的,只有一行與唯一鍵重複使用的行。其他衝突的行被刪除。不正確的值將被截斷爲最接近的匹配可接受值。

不幸的是,它沒有指定哪個價值將被保留。做一些測試似乎喜歡它保持第一次出現,但你永遠無法確定。

如果哪個入口不會打擾您,這是最簡單的解決方案,否則如果您想要更多控制,最好通過臨時表。

命令CREATE UNIQUE PIndex ON table1 (attributeId, entityId, carId);(注意添加的UNIQUE)只會在第一個重複鍵上失敗,並且沒有管理重複項的選項可用。