【问题标题】:Renumber keys in compound unique constraint对复合唯一约束中的键重新编号
【发布时间】:2016-06-19 10:35:41
【问题描述】:

我有一个如下所示的表格:

| id | sub_id | fk_id |
|----|--------|-------|
| 1  | 1      | 1     |
| 2  | 2      | 1     |
| 3  | 3      | 1     |
| 4  | 4      | 1     |
| 5  | 5      | 1     |
| 6  | 1      | 2     |
| 7  | 2      | 2     |
| 8  | 3      | 2     |
| 9  | 4      | 2     |
| 10 | 5      | 2     |

在这个表中id是主键,sub_idfk_id组成一个复合唯一键,其中fk_id是另一个表中的主键。

我发现自己需要能够删除表中的行,然后重新编号 sub_id 以便没有任何间隙,例如删除(1, 1, 1) 以及fk_id=1 各自的sub_id 重新编号为1、2、3、4 等的所有行。

我还需要能够一次删除一行或多行,然后触发重新编号(因为我认为在一次就足够的情况下尝试多次重新编号它们是低效的)。但是,fk_id 的每个值最多有 60 行,但fk_id 的值可能有数千个。

我应该如何重新编号?我认为某种 INSERT ... SELECT 查询,但我无法理解它应该如何工作。

【问题讨论】:

  • 你在做一些奇怪的事情,规范化你的表怎么样?它可以帮助你在路上,阅读关于 1NF
  • 你能澄清一下你认为这很奇怪吗?我看不出它怎么不符合1NF 的标准

标签: mysql database


【解决方案1】:

您可以使用此查询为给定的fk_id 重新编号行:

select t_renum.*, count(t_lower.id) as new_sub_id
from mytable t_renum
join mytable t_lower
    on  t_lower.fk_id = t_renum.fk_id
    and t_lower.id <= t_renum.id
where t_renum.fk_id = @renumber_fk_id
group by t_renum.id

结果可以像这样与原始表连接以进行更新:

update mytable t
join (
    select t_renum.*, count(t_lower.id) as new_sub_id
    from mytable t_renum
    join mytable t_lower
        on  t_lower.fk_id = t_renum.fk_id
        and t_lower.id <= t_renum.id
    where t_renum.fk_id = @renumber_fk_id
    group by t_renum.id 
) t_renum using (id)
set t.sub_id = t_renum.new_sub_id

sqlfiddle

【讨论】:

    【解决方案2】:

    在深入挖掘之后,我发现了另一个answer,它非常简单,并且避免了在许多类似问题中推荐的新表的需要。我将其转换为更适合我需要的存储过程:

    DELIMITER //
    CREATE PROCEDURE reindex (IN fk_key INT UNSIGNED)
    BEGIN
        SET @num := 0;
    
        UPDATE example
            SET sub_id = (@num := @num + 1)
            WHERE fk_id = fk_key
            ORDER BY id;
    END //
    DELIMITER ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-03
      • 2011-05-25
      • 2020-07-22
      • 1970-01-01
      • 1970-01-01
      • 2016-04-12
      相关资源
      最近更新 更多