MySQL技术问询:为唯一值表加索引及生成自定义SID字段
既然你的表所有值都是唯一的,那最适合的就是唯一索引或者主键索引——这俩既能帮你加速查询,还能继续保证数据的唯一性,一举两得。
给你两种常用的操作方式:
- 如果这个唯一字段还没被设为主键,直接把它设为主键就行(主键默认自带唯一约束和非空约束):
ALTER TABLE 你的表名 ADD PRIMARY KEY (唯一字段名);
- 要是你已经有主键了,或者只是想给某个唯一字段单独加索引,就用唯一索引:
-- 方式一:CREATE语句 CREATE UNIQUE INDEX 索引名 ON 你的表名 (唯一字段名); -- 方式二:ALTER TABLE语句 ALTER TABLE 你的表名 ADD UNIQUE INDEX 索引名 (唯一字段名);
这里提个小区别:一个表只能有一个主键,但可以有多个唯一索引;另外唯一索引允许字段存NULL(除非你给字段加了NOT NULL约束),而主键是绝对不允许NULL的,你可以根据自己的需求选。
你的需求是相同Name对应同一个SID,数字后缀按Name的出现顺序递增,用auto_increment肯定不行——它是给每行递增编号,相同Name会得到不同的数字。咱们换个思路,用排名函数来给每个Name分配唯一的序号就行。
方案一:用窗口函数(MySQL 8.0及以上版本支持)
直接用DENSE_RANK()窗口函数给每个不同的Name排个连续的名次,再和Name拼接起来,完美符合你的需求:
SELECT Name, CONCAT(Name, DENSE_RANK() OVER (ORDER BY Name)) AS SID FROM Person;
解释下:DENSE_RANK() OVER (ORDER BY Name)会按Name的字典序排序,给每个不同的Name分配一个连续的数字——Bruno是第一个,得1;Carl是第二个,得2;Danielle第三个,得3。再用CONCAT()把Name和数字拼起来,就得到了你要的SID。
方案二:兼容低版本MySQL(8.0以下)
如果你的MySQL版本比较老,不支持窗口函数,就用子查询来实现:
SELECT p.Name, CONCAT(p.Name, (SELECT COUNT(DISTINCT Name) FROM Person WHERE Name <= p.Name)) AS SID FROM Person p ORDER BY p.Name;
这个逻辑是:对每一行的Name,统计所有字典序小于等于它的不同Name的数量,这个数量就是对应的排名,拼接后就是想要的SID。
不管用哪种方案,查出来的结果都会和你预期的一致:
Name SID
Bruno Bruno1
Carl Carl2
Carl Carl2
Danielle Danielle3
内容的提问来源于stack exchange,提问作者bhazero025

