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