In my Oracle database, I have these values in a column:
6.40.123580
10.10.114580
10.10.114582
I would like to perform a MAX() function on this column, but if I take my example, I never get "10.10.114582". It shows me "6.40.123580".
Is there a solution? Thank you!
CodePudding user response:
Using MAX
directly on the string does not work as it compares the values as strings and looks for the greatest first character then the greatest second character, etc. Since 6
(at the start of 6.40.123580
) is greater than 1
(at the start of 10.10.11458?
) then 6.40.123580
is greater when compared as a string.
What you need to do is split the string on the .
character and then compare the parts numerically.
To do this, you can use simple (fast) string functions to find the positions of the .
separators and then find the sub-strings between those separators to get the numeric components and then take the row with the greatest values in each successive component:
SELECT version_number,
TO_NUMBER(SUBSTR(version_number, 1, sep1 - 1)) AS major,
TO_NUMBER(SUBSTR(version_number, sep1 1, sep2 - sep1)) AS minor,
TO_NUMBER(SUBSTR(version_number, sep2 1)) AS patch
FROM (
SELECT version_number,
INSTR(version_number,'.',1,1) AS sep1,
INSTR(version_number,'.',1,2) AS sep2
FROM table_name
)
ORDER BY major DESC, minor DESC, patch DESC
FETCH FIRST ROW ONLY;
Or, using (slower) regular expressions:
SELECT version_number,
TO_NUMBER(REGEXP_SUBSTR(version_number, '\d ', 1, 1)) AS major,
TO_NUMBER(REGEXP_SUBSTR(version_number, '\d ', 1, 2)) AS minor,
TO_NUMBER(REGEXP_SUBSTR(version_number, '\d ', 1, 3)) AS patch
FROM table_name
ORDER BY major DESC, minor DESC, patch DESC
FETCH FIRST ROW ONLY;
Which, for your sample data:
CREATE TABLE table_name (version_number) AS
SELECT '6.40.123580' FROM DUAL UNION ALL
SELECT '10.10.114580' FROM DUAL UNION ALL
SELECT '10.10.114582' FROM DUAL;
Both output:
VERSION_NUMBER MAJOR MINOR PATCH 10.10.114582 10 10 114582
If you particularly want to use the MAX
aggregation function then you can use MAX() KEEP ()
to only keep the greatest of the component parts:
SELECT MAX(version_number) KEEP (
DENSE_RANK LAST ORDER BY
TO_NUMBER(SUBSTR(version_number, 1, sep1 - 1)),
TO_NUMBER(SUBSTR(version_number, sep1 1, sep2 - sep1)),
TO_NUMBER(SUBSTR(version_number, sep2 1))
) AS max_version_number
FROM (
SELECT version_number,
INSTR(version_number,'.',1,1) AS sep1,
INSTR(version_number,'.',1,2) AS sep2
FROM table_name
);
Which, for the sample data, outputs:
MAX_VERSION_NUMBER 10.10.114582
db<>fiddle here