在 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

应该显示您希望它显示的内容.. 看起来您正在按idnumber 对其进行排序,目前尚未定义为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 字段进行数字排序的主要内容,如果未能解决你的问题,请参考以下文章

mysql 字段类型VARCHAR转换成DECIMAL

mysql varchar排序

mysql 字符串按照数字类型排序

mysql的varchar转换int

mysql varchar 最大可以设置多少

Mysql varchar字段长度越大越好吗?