16

I have a field in one of my SQL tables which stores a version number, like '3.4.23' or '1.224.43'.

Is there a way to use a greater than condition for this field?

SELECT * FROM versions WHERE version_number > '2.1.27'

7
  • You could write a procedure that translates the version number in something comparable and use that WHERE version_normalised(version_number) > version_normalised('2.1.27') Commented Jan 19, 2016 at 12:28
  • How exactly does this work? what is greater than what? is 3.4.23 bigger then 3.224.5? explain your rules. Commented Jan 19, 2016 at 12:28
  • Or you create a version comparer: WHERE version_compare(version_number, '2.1.27') Point is, MySQL does not have this built-in. Commented Jan 19, 2016 at 12:31
  • I have tried with MySQL 8.0. In my column, I have a column version with 3 rows 1.2.3, 1.11.1 1.1.1. I can just simply get the version with "SELECT * FROM versions WHERE version > '1.1.1'" Then I can get 1.2.3 and 1.11.1 successfully. Couldn't just use this to do version comparison? Commented Oct 19, 2018 at 8:26
  • @chan3600 will you get 1.11.1 when you query for version > '1.2.1' ? Commented Oct 19, 2018 at 13:42

5 Answers 5

17

Thanks for the tips @symcbean and @gordon-linoff, my final query looks like this:

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'));

This allows each component to be up to 10 digits long.

It transforms this:

X.XX.XXX > 2.1.27

to this:

'000000000X00000000XX0000000XXX' > '000000000200000000010000000027'
Sign up to request clarification or add additional context in comments.

Comments

6

While it would be possible to write a function which would compare version numbers, is this the right way to solve the problem? Comparing f(x) and f(y) cannot be indexed. If you know that any part of the version number will never exceed, say, 4 digits, then you could create an additional field holding the value padded with 0's (or on Mariadb, use a virtual column) which can be indexed, e.g. 2.1.27 would become '000200010027`.

It would be a lot simpler if you stopped trying to use such a numbering schema and just used integers or datetimes. If you must stick with this numbering, then consider splitting the data into 3 columns.

For a quick hack, if you know that the version number will always have 3 component and each component will always be less than 256, then you could...

SELECT * 
FROM versions 
WHERE INET_ATON(CONCAT(version_number, '.0')) > INET_ATON('2.1.27.0');

5 Comments

Clever use of a IPv4 function; the requirement for "always <256" is however very un-obvious and likely to bite in longer term.
Thanks @symcbean for the inspiration, I can't the INET_ATON, since my version numbers can be greater than 256, but I used your first idea, and you can see my final query in a new answer.
unless I'm missing something, don't need to pad if you are comparing same amount of version parts.. ie INET_ATON('1.0.0') is the same INET_ATON('0.1.0.0').
Padding is a different approach than using inet numbers
sorry, I mean padding right 0, concatenating with '0' on both side of comparison in last proposed solution. It'd just a hack anyway. I agree w you that it shouldn't be used, preferring a different approach on storing data.
1

With multiple conditions, this is a bit of a pain. Here is a brute force approach:

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
      )

Note: the same substring_index() expression can be used on the right-hand side, but using constants makes it simpler to see the logic.

Comments

0

@Adam In case there are short version numbers like v1 or v1.2, better concat version_number like CONCAT(version_number, '.0.0') first

Comments

0

I use the following which works for any version numbers less than 255:

SELECT * FROM versions
WHERE INET_ATON(SUBSTRING_INDEX(CONCAT(version, '.0.0.0'), '.', 4)) > INET_ATON(SUBSTRING_INDEX(CONCAT('2.1.27', '.0.0.0'), '.', 4));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.