获取表中两个UID之间的所有可用UID

时间:2015-06-24 20:34:22

标签: mysql

我有一个UID表是主键。在旧系统中,它不是主键。因此,人们可以将数据插入该字段,但我们不想再这样做了。

在此表中,我在UID 2000和2005之间存在差距(采用2003)。如何获得该差距内的列表整数?

已更新 我实际上不希望2个uid之间的连续数字列表。假设我可能在两个数字之间存在一些UID,但我不知道。我只想获得2个UID之间的可用UID列表

我希望此列表返回:

MISSING
2001
2002
2004

2 个答案:

答案 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数据库中首先测试了这个。

祝你好运!