仅使用SQL使数据库表中的“优先级”编号唯一

时间:2013-12-19 18:56:52

标签: mysql sql database

我们有一个如下所示的数据库表:

RowID   CustomerID  Priority    Data
11      123         1           {some data}
2       123         1           {some data}
3       123         3           {some data}
44      456         1           {some data}
5       456         2           {some data}
61      456         2           {some data}
65      456         2           {some data}
76      456         2           {some data}
96      456         3           {some data}
36      456         4           {some data}
7       123         1           {some data}

这是应该按优先级排序的项目列表。不幸的是,由于系统错误(代码和不正确的约束),一些优先级是重复的。

例如,在我给出的示例中,客户456有三个优先级为2的项目。不幸的是,目前还没有办法知道哪一个实际上应该在插槽2中。

显然,需要纠正系统以防止出现这种情况(并且这已经完成),但我们仍然需要解决客户数据情况。在这个例子中,如果我们专注于修复客户#456的数据,我们能够提出的最佳解决方案是将456行更改为:

RowID   CustomerID  Priority    Data
44      456         1           {some data}
5       456         2           {some data}
61      456         3           {some data}
65      456         4           {some data}
76      456         5           {some data}
96      456         6           {some data}
36      456         7           {some data}

您可以看到优先级增加如下:

  • 第61行增加1,
  • 第65行增加2,
  • 第76行增加3,
  • 第96行增加3,
  • 第36行增加3

这会将数据恢复到没有两个项目共享相同优先级的情况。

我想知道是否有办法在SQL中解决这个问题,或者我是否必须编写一个“修复它”程序来分析一个客户的数据库。

尽我所能,我似乎无法理解如何在直接的SQL中实现这一点。有可能吗?

2 个答案:

答案 0 :(得分:1)

所以你想按customerId,priority,rowId订购,并为每个客户设置优先级1,2,3,4 ......等等,如下面的查询

首先看看newPriority是否是您想要的每一行(sqlFiddle

   SELECT rowId,customerId,priority
       IF(@prevCustomer <> customerId,@priority:=1,@priority:=@priority+1)
          AS newPriority,
       @prevCustomer:=customerId
   FROM YourTable,
        (SELECT @priority:=0,@prevCustomer:=0)dummy
   ORDER BY customerId,priority,rowId

然后如果这是正确的,请检查newPriority列并查看,您可以在下面运行更新(sqlFiddle

UPDATE yourTable T1
INNER JOIN
  (SELECT rowId,customerId,priority
       IF(@prevCustomer <> customerId,@priority:=1,@priority:=@priority+1)
          AS newPriority,
       @prevCustomer:=customerId
   FROM YourTable,
        (SELECT @priority:=0,@prevCustomer:=0)dummy
   ORDER BY customerId,priority,rowId
  )T2
ON T1.rowId = T2.rowId
SET T1.priority = T2.newPriority;

要仅修复客户456 ,您可以在查询结尾添加WHERE T1.customerId=456,如下所示

UPDATE yourTable T1
INNER JOIN
  (SELECT rowId,customerId,priority,
       IF(@prevCustomer <> customerId,@priority:=1,@priority:=@priority+1)
          AS newPriority,
       @prevCustomer:=customerId
   FROM YourTable,
        (SELECT @priority:=0,@prevCustomer:=0)dummy
   ORDER BY customerId,priority,rowId
  )T2
ON T1.rowId = T2.rowId
SET T1.priority = T2.newPriority
WHERE T1.customerId = 456;

答案 1 :(得分:0)

我建议您在事务中放置任何SQL,然后选择所有行以直观地查看它是否是您想要的。然后回滚。只有当您确定其正确时,才将其更改为提交。这样,您就不会破坏数据库数据。或者(并且更好)备份您的数据库,以便您可以恢复它,如果你搞砸了。缺点是如果您需要进行恢复,备份后任何客户都会更改数据库。