Eri*_*ric 13 python mysql sql django natural-sort
我的表中有固件版本字符串(如"4.2.2"或"4.2.16")
我该如何比较,选择或排序?
我不能使用标准字符串比较:SQL看到"4.2.2"大于"4.2.16"
作为版本字符串,我希望4.2.16大于4.2.2
我想考虑固件版本中可能有chars:4.24a1,4.25b3 ...为此,通常,带字符的子字段具有固定长度.
如何进行 ?
And*_*y M 15
如果您的所有版本号都像以下任何一个:
X
X.X
X.X.X
X.X.X.X
Run Code Online (Sandbox Code Playgroud)
其中X是0到255(含)的整数,那么您可以使用该INET_ATON()函数将字符串转换为适合比较的整数.
但是,在应用函数之前,您需要通过向函数X.X.X.X附加必要的数量'.0'来确保函数的参数是表单.要做到这一点,首先需要找出.字符串已经包含多少,这可以这样做:
CHAR_LENGTH(ver) - CHAR_LENGTH(REPLACE(ver, '.', '')
Run Code Online (Sandbox Code Playgroud)
也就是说,字符串中的句点数是删除句点后字符串的长度减去其长度.
然后应该从中减去获得的结果,3并将其'.0'传递给REPEAT()函数:
REPEAT('.0', 3 - CHAR_LENGTH(ver) + CHAR_LENGTH(REPLACE(ver, '.', ''))
Run Code Online (Sandbox Code Playgroud)
这将为我们提供必须附加到原始ver值的子字符串,以符合X.X.X.X格式.因此,它将CONCAT()与...一起传递给函数ver.的,这个结果CONCAT()现在可以直接传递给INET_ATON().所以这就是我们最终获得的:
INET_ATON(
CONCAT(
ver,
REPEAT(
'.0',
3 - CHAR_LENGTH(ver) + CHAR_LENGTH(REPLACE(ver, '.', ''))
)
)
)
Run Code Online (Sandbox Code Playgroud)
这只是一个价值!:)应该为另一个字符串构造一个类似的表达式,之后您可以比较结果.
参考文献:
假设组数为 3 或更少,您可以将版本号视为两个十进制数并相应地对其进行排序。方法如下:
SELECT
ver,
CAST(
SUBSTRING_INDEX(ver, '.', 2)
AS DECIMAL(6,3)
) AS ver1, -- ver1 = the string before 2nd dot
CAST(
CASE
WHEN LOCATE('.', ver) = 0 THEN NULL
WHEN LOCATE('.', ver, LOCATE('.', ver)+1) = 0 THEN SUBSTRING_INDEX(ver, '.', -1)
ELSE SUBSTRING_INDEX(ver, '.', -2)
END
AS DECIMAL(6,3)
) AS ver2 -- ver2 = if there is no dot then 0.0
-- else if there is no 2nd dot then the string after 1st dot
-- else the string after 1st dot
FROM
(
SELECT '1' AS ver UNION
SELECT '1.1' UNION
SELECT '1.01' UNION
SELECT '1.01.03' UNION
SELECT '1.01.04' UNION
SELECT '1.01.1' UNION
SELECT '1.11' UNION
SELECT '1.2' UNION
SELECT '1.2.0' UNION
SELECT '1.2.1' UNION
SELECT '1.2.11' UNION
SELECT '1.2.2' UNION
SELECT '2.0' UNION
SELECT '2.0.1' UNION
SELECT '11.1.1'
) AS sample
ORDER BY ver1, ver2
Run Code Online (Sandbox Code Playgroud)
输出:
ver ver1 ver2
======= ====== ======
1 1.000 (NULL)
1.01 1.010 1.000
1.01.03 1.010 1.030
1.01.04 1.010 1.040
1.01.1 1.010 1.100
1.1 1.100 1.000
1.11 1.110 11.000
1.2.0 1.200 2.000
1.2 1.200 2.000
1.2.1 1.200 2.100
1.2.11 1.200 2.110
1.2.2 1.200 2.200
2.0 2.000 0.000
2.0.1 2.000 0.100
11.1.1 11.100 1.100
Run Code Online (Sandbox Code Playgroud)
笔记:
DECIMAL(6,3)用于说明。如果您希望次要版本号超过 3 位,则相应地进行修改。最后,我找到了另一种对版本字符串进行排序的方法。
我只是在以可排序的方式将字符串存储到数据库之前对字符串进行调整。由于我使用 python Django 框架,我刚刚创建了一个 VersionField,它在存储时对版本字符串进行“编码”,在读取时对其进行“解码”,因此它对于应用程序来说是完全透明的:
这是我的代码:
The justify function :
def vjust(str,level=5,delim='.',bitsize=6,fillchar=' '):
"""
1.12 becomes : 1. 12
1.1 becomes : 1. 1
"""
nb = str.count(delim)
if nb < level:
str += (level-nb) * delim
return delim.join([ v.rjust(bitsize,fillchar) for v in str.split(delim)[:level+1] ])
The django VersionField :
class VersionField(models.CharField) :
description = 'Field to store version strings ("a.b.c.d") in a way it is sortable'
__metaclass__ = models.SubfieldBase
def get_prep_value(self, value):
return vjust(value,fillchar=' ')
def to_python(self, value):
return re.sub('\.+$','',value.replace(' ',''))
Run Code Online (Sandbox Code Playgroud)