I have firmware version strings into my table (like \"4.2.2\" or \"4.2.16\")
How can I compare, select or sort them ?
I cannot use standard strings compariso
I was searching for the same thing and instead ended up doing this -- but staying in mysql :
using this statement
case when version is null then null
when '' then 0
else
preg_replace( '/[^.]*([^.]{10})[.]+/', '$1',
preg_replace('/([^".,\\/_ ()-]+)([".,\\/_ ()-]*)/','000000000$1.',
preg_replace('/(?<=[0-9])([^".,\\/_ ()0-9-]+)/','.!$1',version
)))
end
I'll break down what that means:
preg_replace
is a function that the UDF library created. Because it's a UDF you can just call it from any user or dbspace like that^".,\\/_ ()
right now i'm considering all of these characters as separators or traditional "dots" in a versionpreg_replace('/(?<=[0-9])([^".,\\/_ ()0-9-]+)/','.!$1',version)
means to replace all the non-"dots" and non-numbers that are preceded by a number to be preceded by a "dot" and an exclamation point. preg_replace('/([^".,\\/_ ()-]+)([".,\\/_ ()-]*)/','000000000$1.', ...)
means to additionally replace all the "dots" with actual dots and to pad all the numbers with 9 zero's. Also any adjacent dots would be reduced to 1.preg_replace( '/0*([^.]{10})[.]+/', '$1', ... )
means to additionally strip all the number blocks down to only 10 digits long and to preserve as many blocks as needed. I wanted to force 6 blocks to keep it under 64-bytes but needing 7 blocks was surprisingly common and thus necessary for my accuracy. Also needed blocks of 10 so 7 blocks of 9 was not an option. But the variable length is working well for me. -- remember strings are compared left to rightSo now I can handle versions like:
1.2 < 1.10
1.2b < 1.2.0
1.2a < 1.2b
1.2 = 1.2.0
1.020 = 1.20
11.1.1.3.0.100806.0408.000 < 11.1.1.3.0.100806.0408.001
5.03.2600.2180 (xpsp_sp2_rtm.040803-2158)
A.B.C.D = a.B.C.D
A.A < A.B
I chose exclamation point because it sorts in the collations sequences (that I'm using anyway) before 0. It's relative sort to 0 allows letters like b and a when used immediately adjacent to a number above to be treated like a new section and be sort before 0 -- which is the padding I am using.
I am using 0 as padding so that vendor's mistakes like moving from a fixed 3 digit block to a variable one don't bite me.
You can easily choose more padding if you want to handle silly versions like "2.11.0 Under development (unstable) (2010-03-09)" -- the string development
is 11 bytes.
You can easily request more blocks in the final replace.
I could have done more but I was trying to do a as few paces as possible with a high-level of accuracy since I have several millions records to scan regularly. If anyone sees an optimization please repsond.
I chose to keep it as a string and not cast into a number because the cast has a cost and also letters are important as we saw. One thing i was thinking about is doing a test on the string and returning an option that isn't as many passes or less expensive function for tidier cases. like 11.1.1.3
is a very common format