2016-01-19 43 views
4

我有一个字段在我的一个SQL表中存储版本号,如3.4.23或1.224.43。MySQL查询 - 比较版本号

有没有办法使用大于条件的这个字段?

SELECT * FROM versions WHERE version_number > '2.1.27'

+0

您可以编写一个翻译的东西可比版本号的程序,并使用'WHERE version_normalised(VERSION_NUMBER)> version_normalised(” 2.1.27')' –

+0

这个工作到底如何?什么比什么更大?是3.4.23然后是3.224.5?解释你的规则。 – sagi

+0

或者你创建一个版本比较器:'WHERE version_compare(version_number,'2.1.27')'Point是,MySQL没有这个内置的。 –

回答

4

感谢您的提示@symcbean和@ gordon-linoff,我的最终查询如下所示:

SELECT * 
FROM versions WHERE CONCAT(
     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(version_number, '.', 1), '.', -1), 10, '0'), 
     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(version_number, '.', 2), '.', -1), 10, '0'), 
     LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(version_number, '.', 3), '.', -1), 10, '0') 
     ) > CONCAT(LPAD(2,10,'0'), LPAD(1,10,'0'), LPAD(27,10,'0')); 

这允许每个组件长达10位数。

它把这样的:

3.11.9 > 2.1.27 

这样:

'000000000300000000110000000009' > '000000000200000000010000000027' 
1

随着多个条件,这是一个有点疼痛。这里是一个强力的方法:

where substring_index(version_number, '.', 1) + 0 > 2 or 
     (substring_index(version_number, '.', 1) = '2' and 
     substring_index(version_number, '.', 2) + 0 > 2.1 
    ) or 
     (substring_index(version_number, '.', 2) = '2.1' and 
     substring_index(version_number, '.', -1) + 0 > 27 
    ) 

注:同一substring_index()表达可以在右侧可以使用,但使用常数可以更容易看到的逻辑。

2

尽管可以编写一个比较版本号的函数,但这是解决问题的正确方法吗?比较f(x)和f(y)不能被索引。如果您知道版本号的任何部分永远不会超过4位数字,那么您可以创建一个附加字段,其中保留用0填充的值(或在Mariadb上,使用虚拟列),可以对其进行索引,例如, 2.1.27将变成'000200010027`。

如果您停止尝试使用这样的编号模式并仅使用整数或日期时间,那将会简单得多。如果你必须坚持这个编号,那么考虑将数据分成3列。

对于一个快速的黑客,如果你知道的版本号将始终有3个组成部分和每个组件将始终小于256,那么你可以...

SELECT * 
FROM versions 
WHERE INET_ATON(CONCATversion_number, '.0') > INET_ATON('2.1.27.0'); 
+0

巧妙使用IPv4功能;但对于“始终<256”的要求是非常不明显的,并且可能会长期存在。 – Piskvor

+0

感谢@symcbean的灵感,我不能INET_ATON,因为我的版本号可以大于256,但我使用了你的第一个想法,你可以在一个新的答案中看到我的最终查询。 – Adam

+0

除非我遗漏了一些东西,如果你比较相同数量的版本部分,则不需要填充。即INET_ATON('1.0.0')'与INET_ATON('0.1.0.0')'是相同的。 –