2012-12-28 49 views
2

我有一个较旧的数据库(在某些真正有疑问和不明确的原因,我不喜欢在这里放太多话题)我想随机化或洗牌主键。基于现有值随机化主键

我现在有自动增加Mysql数据库表中的字段。

我没有太多的关系,那些存在的没有定义为外键。这些关系不需要保存。

所有我正在寻找的是采取主键的当前值和一个随机值掉那些喜欢的替换:

ID := new(ID) 

凡新功能从集合返回一个值所有OLD ID与1:1匹配。例如。

2 := 3 
3 := 2 

但不是

2 := 3 
3 := 3 

有没有办法改变与(理想)单个SQL每桌查询数据库中的数据?

编辑:我没有真正严格的要求。如果有帮助,考虑对数据库拥有独占访问权限,包括来回更改主键的限制,例如,修改表,执行操作,将表更改为以前的模式。也可以为新(或旧)PK值添加另一列。

+0

只有当你删除主键约束,然后重新创建它。 –

+0

@ypercube:这是一个选项。更改值可以在“未安装”的“快照”上完成。因此,在主键更改查询旁边没有其他查询数据库。 – hakre

+0

实际上有几个部分 - 是否可以在列中混洗值?是否有可能只使用基于集合的操作(即不是编程方式)在列中混合值?是否有可能在自动增量网主键列中重新排序值(使用先前的方法)? – 2012-12-28 01:13:52

回答

5

的程序只是一个scetch。创建两个临时表

CREATE TABLE temp_old 
(ai INT NOT NULL AUTO_INCREMENT 
, id INT NOT NULL 
, PRIMARY KEY (ai) 
, INDEX old_idx (id, ai) 
) ENGINE = InnoDB ; 

CREATE TABLE temp_new 
(ai INT NOT NULL AUTO_INCREMENT 
, id INT NOT NULL 
, PRIMARY KEY (ai) 
, INDEX new_idx (id, ai) 
) ENGINE = InnoDB ; 

复制id值按不同的顺序,以两个表(随机在第二表):

INSERT INTO temp_old 
    (id) 
SELECT id 
FROM tableX 
ORDER BY id ; 

INSERT INTO temp_new 
    (id) 
SELECT id 
FROM tableX 
ORDER BY RAND() ; 

然后我们删除主键:

ALTER TABLE tableX 
    DROP PRIMARY KEY ; 

运行实际的UPDATE声明:

UPDATE tableX AS t 
    JOIN temp_old AS o 
    ON o.id = t.id 
    JOIN temp_new AS n 
    ON n.ai = o.ai 
SET t.id = n.id ; 

然后重新创建主键和删除临时表:

ALTER TABLE tableX 
    ADD PRIMARY KEY (id) ; 

DROP TABLE temp_old ; 
DROP TABLE temp_new ; 

测试中SQL-Fiddle

1

您可以创建一个存储过程来创建一个包含所有ID的临时表,然后您可以遍历每个记录,用临时表中的ID替换ID,然后从临时表中删除该ID。我不相信有一种方法可以在单个查询中完成您正在讨论的内容。

+0

有道理。我也可以想象添加另一个字段,以便将旧的主键值保留在新的字段值的旁边。我可以问你,如果你可以分享一些SQL(不需要,只是问),展示如何创建和填充这样一个临时表?这是否真的需要存储程序? – hakre

+2

我知道这是可行的我描述的方式,虽然我不完全确定的语法。对于我自己的学习,我会在接下来的一个小时左右工作,看看我能否实现它。我会分享结果,如果我得到它。 – Ethan

+0

这很好,但你不必因为我在问就这么做。 (好吧,我知道我有时也这样做,如果我发现一个有趣的问题,所以我也不会阻止你);) – hakre

3

以下是按照表格顺序创建ID列表的一种技术,以及从1开始的连续编号,它还以随机顺序创建了您的ID列表以及从1开始的连续编号。然后更新基于匹配顺序号的id。

rand()函数的性能有问题,(它是随机性的)。

如果您的密钥从1开始已经是连续的,那么可以简化它。

Update 
    Test as t 
    Inner Join (
    Select 
     @rownum2 := @rownum2 + 1 as rank, 
     t2.id 
    From 
     Test t2, 
     (Select @rownum2:= 0) a1 
) as o on t.id = o.id 
    Inner Join (
     Select 
     @rownum := @rownum + 1 as rank, 
     t3.id 
     From 
     (Select id from Test order by Rand()) t3, 
     (Select @rownum:= 0) a2 
) as n on o.rank = n.rank 
Set 
    t.id = n.id 

http://sqlfiddle.com/#!2/3f354/1

+0

@Conrad:它似乎工作(现在) –

+0

@ConradFrix但它不工作如果有一个主键约束。 –

+0

@ypercube是的,你说得对 –