这里是我微不足道的解决方案:向用户表中添加一个varchar列(例如,称为username_string_part
)以存储用户名的字符串部分,并在第二个int列(例如username_number_part
)中存储数字部分。所以superman1在username_string_part
列中被分成“超人”,在username_number_part
中被分成“1”。如果您不期望大量重复的username_string_part条目,则还可以在两列或仅在username_string_part上创建索引。因此,在MySQL中,你创建的表是这样的)。
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(25) NOT NULL default '',
`username_string_part` varchar(25) NOT NULL default '',
`username_number_part` int(11) NOT NULL default 0,
PRIMARY KEY (`id`),
KEY `ix_username_string_part` (`username_string_part`)
) TYPE=MyISAM AUTO_INCREMENT=1;
(请注意,用户名“超人”有一个默认的零username_number_part
- 这很重要)
一旦你有几个条目,你的数据将是这个样子:
+----+-----------+----------------------+----------------------+
| id | username | username_string_part | username_number_part |
+----+-----------+----------------------+----------------------+
| 1 | superman | superman | 0 |
| 2 | superman1 | superman | 1 |
| 3 | superman3 | superman | 3 |
+----+-----------+----------------------+----------------------+
然后,它的选择是没有在数据库中username_number_part
价值“本身加一”的username_number_part
最小值的情况。所以对于用户名“超人”:
select min(username_number_part) + 1 as min_number_available from users
where username_string_part = 'superman' and username_number_part not in
(select username_number_part - 1 from users where
username_string_part = 'superman');
返回值,min_number_available
,是NULL
如果这是该用户名的第一个实例 - 这样他们就可以拥有它 - 或者下一个空闲时隙的整数,否则。然后,您建议建议用户名为"superman" + min_number_available
。你可以在查询中进行concat或不按你喜欢的方式。使用上面的示例数据,您将返回值“2”。
缺点:它会添加存储(列和索引),并且放慢插入速度。它也没有自然区分“超人001”和“超人01”。 (虽然如果您将前导零作为username_string_part
的一部分处理,那么“superman001”将被拆分为“超人00”和“1”。)
上行:这是对索引列的单个查询。
毕竟,如果一个站点有太多的用户名重复,那么在多个数据库查询中执行for循环确实很糟糕,那么我会感到惊讶。
两件小事:1。作为一个用户,我讨厌这个 - 我想要一个唯一的用户名,而不是我的用户名和一些数字。确保它是用户需要的东西,而不仅仅是您想要构建的功能。 2.确保您的解决方案不会引入任何安全问题,因为它允许恶意用户找出需要的名称,并且可能是吸取服务器资源的一种方式。 – Tom 2010-01-15 13:58:43
用户名以'01010101'和'h4xx0r1337'这样的数字结尾如何?使用'99'前是否有固定范围的'00'? – BalusC 2010-01-15 14:03:45
@Tom:客户的决定 @BalusC:固定范围就足够了 – 2010-01-15 15:53:50