在 MySQL 中对 varchar 字段进行数字排序
Posted
技术标签:
【中文标题】在 MySQL 中对 varchar 字段进行数字排序【英文标题】:Sorting varchar field numerically in MySQL 【发布时间】:2011-06-08 21:08:58 【问题描述】:我有一个number
类型为varchar
的字段。即使它是varchar
类型,它也存储带有可选前导零的整数值。排序按字典顺序排列它们("42"
在"9"
之前)。如何按数值排序("9"
排在"42"
之前)?
目前我使用查询:
SELECT * FROM table ORDER BY number ASC
【问题讨论】:
number
是一个字符串字段,对吧?因为这是按字典顺序排列的。
您应该将列类型更改为 int 并使用 zerofill(如果您想保留 00100)
@ajreal,使用 zerofill(非标准)没有任何好处,因为它会在获取该字段时添加更多前导零。所以在这种情况下这无济于事。
【参考方案1】:
试试这个
SELECT * FROM table_name ORDER BY CAST(field_name as SIGNED INTEGER) ASC
【讨论】:
这对大型数据库有效吗? @marcog:正如 paxdiable 的回答中提到的,这将是一个性能杀手。 即使它有性能问题,它仍然可以工作。总比没有好。【参考方案2】:有几种方法可以做到这一点:
-
将它们存储为数值而不是字符串。您已经忽略了这一点,因为您希望像
00100
这样的字符串保持原样并带有前导零。
按转换为数字的字符串排序。这将起作用,但请注意,它是体面大小的数据库的性能杀手。每行函数并不能很好地扩展。
添加第三列,它是字符串和索引的数字等价物。然后使用insert
/update
触发器确保在字符串列更改时正确设置。
由于绝大多数数据库的读取频率远高于写入频率,因此上面的第三个选项将计算成本(在 insert
/update
完成)摊销到所有选择中。您的选择会非常快,因为它们使用数字列进行排序(并且没有每行函数)。
您的插入和更新速度会变慢,但这是您付出的代价,老实说,这是值得付出的。
触发器的使用维护了表的 ACID 属性,因为两列保持一致。众所周知,在大多数性能优化中,您通常可以以空间换时间。
我们在许多情况下都使用了这个“技巧”,例如将姓氏的小写版本与原始版本一起存储(而不是使用 tolower
之类的东西)、识别字符串的长度以查找所有具有 7 个字符的用户那些(而不是使用len
)等等。
请记住,只要您了解(并减轻)后果,就可以从第三范式恢复性能。
【讨论】:
【参考方案3】:其实我发现了一些有趣的东西:
SELECT * FROM mytable ORDER BY LPAD(LOWER(mycol), 10,0) DESC
这使您可以像这样对字段进行排序:
1
2
3
10
A
A1
B2
10A
111
【讨论】:
+ 1 因为这个解决方案只能完美地解决字母数字。大量数据的性能如何?如果您的数据有 10 位以上的数字,明智的做法是将 LPAD 长度增加 10 以上。【参考方案4】:SELECT * FROM table ORDER BY number + 0
【讨论】:
所以这种方式 number 将转换为 int。好主意! 我还使用 + 0.0 来获得一个浮点数以正确排序我的版本字段。谢谢! +1 如果列数据类型是字符串并且值只能是数字。如果值是数字和字母,它将失败【参考方案5】:我刚刚学到的技巧。在 varchar 字段顺序子句中添加“+0”:
SELECT * FROM table ORDER BY number+0 ASC
我现在在上面看到了这个答案。我想知道这是否是对字段和整数的类型转换。我没有比较性能。工作得很好。
【讨论】:
哦,是的。这也是一个古老的 Perl 技巧。我有另一种对 varchar 字段进行排序以获得此类结果的方法,现在我很想用这种相当模糊但简单的 WTDI 替换它。 +1 如果列数据类型是字符串并且值只能是数字。如果值是数字和字母,它将失败【参考方案6】:对于具有 Er353、ER 280、ER 30、ER36 等值的表 默认排序将给出 ER280 ER30 ER353 ER36
SELECT fieldname, SUBSTRING(fieldname, 1, 2) AS bcd,
CONVERT(SUBSTRING(fieldname, 3, 9), UNSIGNED INTEGER) AS num
FROM table_name
ORDER BY bcd, num;
结果将按此顺序排列 ER30 ER36 ER280 ER353
【讨论】:
【参考方案7】:您可以使用以下 sql 查询根据您的要求获得订单
SELECT * FROM mytable ORDER BY ABS(mycol)
【讨论】:
【参考方案8】:给定一个包含VARCHAR
的列username
,如下所示:
username1
username10
username100
可以做到:
SELECT username,
CONVERT(REPLACE(username, 'username', ''), UNSIGNED INTEGER) AS N
FROM users u
WHERE username LIKE 'username%'
ORDER BY N;
它并不便宜,但可以。
【讨论】:
【参考方案9】:SELECT * FROM table ORDER BY number ASC
应该显示您希望它显示的内容.. 看起来您正在按id
或number
对其进行排序,目前尚未定义为integer
。
【讨论】:
您将“数字”字段设置为 int 还是 varchar? @wow 为什么是 varchar?你能改变它还是为时已晚?【参考方案10】:mysql ORDER BY 按正确顺序对字母数字进行排序
示例:
SELECT `alphanumericCol` FROM `tableName` ORDER BY
SUBSTR(`alphanumericCol` FROM 1 FOR 1),
LPAD(lower(`alphanumericCol`), 10,0) ASC
输出:
0
1
2
11
21
100
101
102
104
S-104A
S-105
S-107
S-111
【讨论】:
【参考方案11】:粗略准备:按 1*field_name 排序
【讨论】:
以上是关于在 MySQL 中对 varchar 字段进行数字排序的主要内容,如果未能解决你的问题,请参考以下文章