How to compare software versions using SQL Server?
There was a very good solution from a duplicate question here: How to compare SQL strings that hold version numbers like .NET System.Version class?
After playing with the query for a while, I learned that it was not able to compare the last part when there are 4 or more parts (say, if the version number was 1.2.3.4, it would always treat the last one as 0). I have fixed that issue as well as came up with another function to compare two version numbers.
CREATE Function [dbo].[VersionNthPart](@version as nvarchar(max), @part as int) returns int as
Begin
Declare
@ret as int = null,
@start as int = 1,
@end as int = 0,
@partsFound as int = 0,
@terminate as bit = 0
if @version is not null
Begin
Set @ret = 0
while @partsFound < @part
Begin
Set @end = charindex('.', @version, @start)
If @end = 0 -- did not find the dot. Either it was last part or the part was missing.
begin
if @part - @partsFound > 1 -- also this isn't the last part so it must bail early.
begin
set @terminate = 1
end
Set @partsFound = @part
SET @end = len(@version) + 1; -- get the full length so that it can grab the whole of the final part.
end
else
begin
SET @partsFound = @partsFound + 1
end
If @partsFound = @part and @terminate = 0
begin
Set @ret = Convert(int, substring(@version, @start, @end - @start))
end
Else
begin
Set @start = @end + 1
end
End
End
return @ret
End
GO
CREATE FUNCTION [dbo].[CompareVersionNumbers]
(
@Source nvarchar(max),
@Target nvarchar(max),
@Parts int = 4
)
RETURNS INT
AS
BEGIN
/*
-1 : target has higher version number (later version)
0 : same
1 : source has higher version number (later version)
*/
DECLARE @ReturnValue as int = 0;
DECLARE @PartIndex as int = 1;
DECLARE @SourcePartValue as int = 0;
DECLARE @TargetPartValue as int = 0;
WHILE (@PartIndex <= @Parts AND @ReturnValue = 0)
BEGIN
SET @SourcePartValue = [dbo].[VersionNthPart](@Source, @PartIndex);
SET @TargetPartValue = [dbo].[VersionNthPart](@Target, @PartIndex);
IF @SourcePartValue > @TargetPartValue
SET @ReturnValue = 1
ELSE IF @SourcePartValue < @TargetPartValue
SET @ReturnValue = -1
SET @PartIndex = @PartIndex + 1;
END
RETURN @ReturnValue
END
Usage/Test case:
declare @Source as nvarchar(100) = '4.9.21.018'
declare @Target as nvarchar(100) = '4.9.21.180'
SELECT [dbo].[CompareVersionNumbers](@Source, @Target, DEFAULT) -- default version parts are 4
SET @Source = '1.0.4.1'
SET @Target = '1.0.1.8'
SELECT [dbo].[CompareVersionNumbers](@Source, @Target, 4) -- typing out # of version parts also works
SELECT [dbo].[CompareVersionNumbers](@Source, @Target, 2) -- comparing only 2 parts should be the same
SET @Target = '1.0.4.1.5'
SELECT [dbo].[CompareVersionNumbers](@Source, @Target, 4) -- only comparing up to parts 4 so they are the same
SELECT [dbo].[CompareVersionNumbers](@Source, @Target, 5) -- now comparing 5th part which should indicate that the target has higher version number
declare @v1 varchar(100) = '5.12'
declare @v2 varchar(100) = '5.8'
select
case
when CONVERT(int, LEFT(@v1, CHARINDEX('.', @v1)-1)) < CONVERT(int, LEFT(@v2, CHARINDEX('.', @v2)-1)) then 'v2 is newer'
when CONVERT(int, LEFT(@v1, CHARINDEX('.', @v1)-1)) > CONVERT(int, LEFT(@v2, CHARINDEX('.', @v2)-1)) then 'v1 is newer'
when CONVERT(int, substring(@v1, CHARINDEX('.', @v1)+1, LEN(@v1))) < CONVERT(int, substring(@v2, CHARINDEX('.', @v2)+1, LEN(@v1))) then 'v2 is newer'
when CONVERT(int, substring(@v1, CHARINDEX('.', @v1)+1, LEN(@v1))) > CONVERT(int, substring(@v2, CHARINDEX('.', @v2)+1, LEN(@v1))) then 'v1 is newer'
else 'same!'
end
You could use hierarchyid
Which you can use by putting a /
at the end and start of the string and casting it
e.g.
SELECT CASE WHEN cast('/5.12/' as hierarchyid) > cast('/5.8/' as hierarchyid) THEN 'Y' ELSE 'N' END
That returns a Y