2015-09-21 135 views
1

我有這樣的表結構:MySQL的更新SORT_ORDER具有唯一約束的領域導致違反唯一約束

表1:id, group_id, label, sort_order

鍵:PK: id, UNIQUE: group_id+sort_order, INDEX: group_id

的樣本數據:

id group_id label  sort_order 
50 1   Field 1  1 
51 1   Field 2  2 
52 1   Field 3  3 

(group_id, sort_order)是一個獨特的關鍵。

要更新前端記錄的排列,按條目按順序使用sort_order字段。用戶可以通過在前端拖動標籤來更新訂單,該標籤通過ID,例如:52, 51,50,然後將其視爲新訂單/排序。

預期的結果:

id group_id label  sort_order 
50 1   Field 1  3 
51 1   Field 2  2 
52 1   Field 3  1 

過程中應與新sort_order值更新所有3條記錄。樣品更新查詢:

UPDATE Table1 SET sort_order = 1 WHERE id = 52 AND group_id = 1 

然而,由於排序順序是唯一鍵的一部分,因爲group_id,sort_order鍵已經存在拋出錯誤。

我做了一個駭人的解決方法,我更新了排序順序兩次,例如:將其更新爲更高的值,例如:sort_order = actual_order + 1000然後使用實際值再次更新,例如:sort_order = actual_order

什麼是更好的方法?我應該完全刪除唯一的密鑰嗎?

-

編輯

-

爲了給問題的一個更好的視野,這裏是我的PHP代碼:

樣品fieldIds:52,51,5050,51,5251,52,50。序列決定了新的排序。

public function updateSort($projectId, $groupId, $subgroupId, array $fieldIds) 
{ 
    // Other stuff 
    // ... 

    $statement = create_a_prepared_statement(); // ... 

    // Updating sort_order directly would result to unique key violation 
    // so change the sort_order into some negative numbers and re-sort with 
    // the actual orders 
    foreach ($fieldIds as $sortIndex => $fieldId) { 
     $sort = $sortIndex - 1000; 
     $statement->execute(array(
      'id' => $fieldId, 
      'project_id' => $projectId, 
      'group_id' => $groupId, 
      'subgroup_id' => $subgroupId, 
      ':0' => $sort, 
     )); 
    } 

    // Now sort it correctly 
    foreach ($fieldIds as $sortIndex => $fieldId) { 
     $sort = $sortIndex + 1; 
     $statement->execute(array(
      'id' => $fieldId, 
      'project_id' => $projectId, 
      'group_id' => $groupId, 
      'subgroup_id' => $subgroupId, 
      ':0' => $sort, 
     )); 
    } 

    return true; 
} 
+0

是否有一個原因,您不能將sort_order移出PK,並將實際的唯一ID放在那裏? –

+2

你的破解是一個合理的方法。我通常使用負值,所以如果出現問題,它們立即顯而易見。另一種可能性是使用NULL值。 –

+0

@MutuYolbulan。 。 。 OP聲明,這個組合是一個*唯一*鍵,而不是*主鍵*。我猜想'id'是主鍵。 –

回答

0

當你有這樣的嚴格約束,你將不得不使用一箇中間值:

UPDATE Table1 SET sort_order = -1 WHERE id = 52 AND group_id = 1; 
UPDATE Table1 SET sort_order = 3 WHERE id = 50 AND group_id = 1; 
UPDATE Table1 SET sort_order = 1 WHERE id = 52 AND group_id = 1; 

-1是中間值。

整個過程:

  • 地點SORT_ORDER用於在中間值記錄1給定組;
  • 將記錄2的sort_order放置到期望值;
  • 將記錄1的sort_order放置到期望值;

因此,要保持約束條件,您將不得不更新2條記錄,並且1條記錄甚至2條。

1

考慮你在這個聲明中寫道:

I did a hackish workaround where ... 

我將執行這句話的前半部分,

sort_order = actual_order + 1000 

然後停止(這意味着你完成)。

你絕不會在100年中遇到最大值溢出。如果擔憂,那麼讓你的年度活動(通過創建活動)提醒你自己的關注程度,並將該團隊重新調整回1+。

但是你需要更新任何給定的組2M次溢出。

+0

這是一個有趣的方法。看到我的編輯與示例PHP代碼。儘管這樣仍然會導致重複,因爲實際順序總是以'1'開始,例如:'1,2,3'。也許下次我排序時,我會用負值,然後在下一排,積極的價值。我不知道,但這可能對我目前的代碼有所幫助。謝謝 – Lysender

+0

會很高興地通過PHP運行它,並幫助早日或早些時候弄清楚它。有點享受足球比賽:) – Drew

0

從它的外觀來看,您的前端正在生成一次更新一行的更新語句。如果在任何時候更新語句導致2行具有相同的值,則會導致唯一的鍵違規。我認爲你應該考慮找到一種方法來在一個語句中用排序值更新所有行。我不熟悉mysql,但我熟悉sql服務器。在sql服務器中,我將表複製到臨時表並找出那裏的新排序。然後執行更新語句,將新的排序值以一個語句複製回原始表。