我有一个UID表是主键。在旧系统中,它不是主键。因此,人们可以将数据插入该字段,但我们不想再这样做了。
在此表中,我在UID 2000和2005之间存在差距(采用2003)。如何获得该差距内的列表整数?
已更新 我实际上不希望2个uid之间的连续数字列表。假设我可能在两个数字之间存在一些UID,但我不知道。我只想获得2个UID之间的可用UID列表
我希望此列表返回:
MISSING
2001
2002
2004
答案 0 :(得分:2)
有关如何创建列出范围内所有数字的表格,请参阅Generating a range of numbers in MySQL。然后做:
set @start = 2000;
set @end = 2005;
SELECT n AS missing
FROM number_table AS nt
LEFT JOIN your_table AS t ON nt.n = t.uid
WHERE n BETWEEN @start AND @end
AND t.uid IS NULL
答案 1 :(得分:1)
以下各节的摘要。
第1节模仿ID中存在空白的表格,如您的问题
第2节显示了将400万行表与pk递增放在一起的快速方法。 完全没有用于此但也许有用。 如果它似乎留下了半个想法,那是因为它完全没用了
第3节创建一个受第2节启发的表格,为您提供表格 它只是一个工作台,其中重要的排序,插入和处理它
要使用的新ID(pk) 你当前的id(容易出错的那个) 以及一个表示是否已处理的列,以便您可以批量执行这些操作 第3节是行动的地方
xxxxxxxxxxxxxxxxxxxxxxxxxx
第1节:
create table tbl1
( // this mimicks your current table. naturally you have one already
id bigint not null auto_increment primary key,
thing varchar(100) -- whatever columns you have
)engine=MyISAM;
insert tbl1(thing) values('a'),('a'),('b');
show table status from test; -- auto_increment=4, max is 3
alter table tbl1 auto_increment=2000;
insert tbl1(thing) values('a'),('a'),('b');
alter table tbl1 auto_increment=100000; -- 100k
insert tbl1(thing) values('a'),('a'),('b');
alter table tbl1 auto_increment=110000; -- 110k
insert tbl1(thing) values('a'),('a'),('b');
alter table tbl1 auto_increment=2000000; -- 2m
insert tbl1(thing) values('a'),('a'),('b');
show table status from test; -- auto_increment=2000003, max is 2000002
select count(*) from tbl1 -- 15 rows
xxxxxxxxxxxxxxxxxxxxxxxxxx
第2节:
create table idFix
( colIs bigint auto_increment primary key, -- Is your Key
colShouldBe bigint null -- Should be your new Key
processedYet tinyint null -- 1 if processed
)engine=myisam;
insert into idFix(colIs) values(null); -- prime it with 1 row
-- this is pretty fast, don't laugh
-- run the following line 22 times
insert into idFix(colIs) select null from idFix;
-- you now have 4.2m rows in tbl2 (4,194,304)
select count(*) from idFix
select count(*) from idFix
where colIs not in (select id from tbl1)
-- 4,194,289
xxxxxxxxxxxxxxxxxxxxxxxxxx
第3节:
首先备份数据。然后在以下<{p>的scratch
数据库中执行测试
create table idFix2
( yourIdShouldBe bigint auto_increment primary key, -- This becomes what your new key should be
yourIdIs bigint null, -- This is what your gap-prone id is right now
processedYet tinyint null -- 1 if processed, null otherwise
)engine=myisam;
-- the order by is important
insert into idFix2(yourIdIs,processedYet)
select id,null from tbl1 order by id
-- again order by in above stmt is important
现在你有一张表,你的密钥应该是什么,你的密钥是什么,processedYet
是空的。
在存储过程或前端代码中的batches
中执行它们(比如java / c#,无论如何)
从上到下进行这些操作非常重要。任何其他方式都会搞砸你的数据
我提到它从上到下是很重要的吗?
我会想到让每个人都离开系统并要求锁定表格 只有你知道你的系统而不是我们。
select *
from idFix2
where processedYet is null and yourIdShouldBe<>yourIdIs
order by yourIdShouldBe -- order is important
limit 2 -- you might want to choose a bigger number :>
我提到它从上到下很重要吗?
以下是使用上面选择stmt
的结果集的流程(a)获得结果集中的下一行
(b)insert
新的父记录使用来自tbl1数据的数据回到tbl1
行yourIdIs
中的数据,但插入的内容为pk = yourIdShouldBe
插入内容将保证您不会在下面调整的孩子中获得外键约束
(c)update
children
使用旧版yourIdIs
挂起新版yourIdShouldBe
在他们的表中(可能有这些表的scads)。孩子们的外键约束
将被尊重,因为新的父行已经从步骤(b)
(d)从tbl1删除父行,其中pk为yourIdIs
。不要害怕这会导致更多
差距,因为这些将基于循环通过(a)填充,这将填充它们
(e)为步骤(a)结果集中处理的行更新idFix2 set processedYet
= 1
(f)GoTo(a)
当你不再有processedYet
= null时,你差不多完成了
将新的auto_increment值设置为它应该是什么(在tbl1中超过max(id)1,让我们调用该数字nnnn)
alter table tbl1 auto_increment=nnnn;
xxxxxxxxxxxxxxxxxxxxxxxxxx
请注意以下内容
show table status from test where name like 'tbl1%'; -- auto_increment=2000003
我在slot4中没有任何内容,2000将成为第4个插槽
insert tbl1(id,thing) values(4,'stuff from record2000 you get the drift');
show table status from test where name like 'tbl1%'; -- auto_increment=2000003 is left as is
因此,您可以自由填补空白,而无需使用auto_increment直到最后
就在那里,你的差距消失了。如果失败,请考虑休假。
哦,我忘记了,无论如何,你在scratch
数据库中首先测试了这个。