MySQL使用唯一约束更新sort_order字段会导致唯一约束违规

时间:2015-09-21 01:26:13

标签: mysql sorting duplicates constraints unique

我有这个表结构:

表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)是唯一键。

要更新前端记录的排列,{by 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

但是,由于sort_order是唯一键的一部分,因此group_id,sort_order键已存在,因此会抛出错误。

我做了一个hackish解决方法,我更新排序顺序两次,例如:将其更新为更高的值,例如:sort_order = actual_order + 1000然后使用实际值再次更新,例如:sort_order = actual_order。< / p>

什么是更好的方法?我应该完全删除唯一键吗?

-

修改

-

为了更好地了解问题,这是我的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;
}

4 个答案:

答案 0 :(得分:1)

考虑您在本声明中所写的内容:

I did a hackish workaround where ...

我会执行该短语的前半部分,

sort_order = actual_order + 1000

然后停止(意味着你已经完成)。

您将永远不会在100年内遇到最大值溢出。如果这是令人担忧的,请让您的年度活动(通过创建活动)提醒您距离它有多远,并将该组重新调整为1+,等等。

但是您需要更新任何给定组 2M 次以获得溢出。

答案 1 :(得分:0)

如果有这样严格的约束,则必须使用中间值:

import java.util.*;
import javax.swing.*;

 public class FibonacciArrayList {

 public static ArrayList<Integer> Fibonacci (Integer Max){

     ArrayList<Integer> A = new ArrayList<Integer>();
   int n0;
   int n1;
   int n2;

   for(int i= 0; i = max; i++){
     n2= n1 + n0;
     system.out.println(n2);
     n0=n1;
     n1=n2;

  return A;
}


  public static void main (String[] arg){
    Integer max;
    String Title = "Fibonacci ArryList";
    String data = JOptionPane.showInputDialog(null, "Enter the upper bound",    Title, 1);
  max = new Integer(data);
    ArrayList<Integer> A = Fibonacci(max);
    System.out.println("There are " + A.size()+ " Fibonacci numbers less than "+max);

    }

}

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置于中间值;
  • 将记录2的sort_order放置到所需的值;
  • 将记录1的sort_order放置到所需的值;

因此,为了保持约束,您将始终更新2条记录,1条记录甚至2条记录。

答案 2 :(得分:0)

从它的外观来看,您的前端正在生成一次更新一行的更新语句。如果更新语句在任何时候导致2行具有相同的值,则将导致唯一的键冲突。我认为您应该研究一种方法来在一个语句中使用排序值更新所有行。我不熟悉mysql,但我熟悉sql server。在sql server中,我会将表复制到临时表,并在那里找出新的排序。然后执行update语句以在一个语句中将新排序值复制回原始表。

答案 3 :(得分:-1)

您可以使用case语句立即更新所有内容

UPDATE Table1 set sort_order =
CASE 
WHEN id = 50 THEN 3
WHEN id = 51 THEN 1
WHEN id = 52 THEN 2
END