How to compare software versions using SQL Server?

后端 未结 16 2227
清酒与你
清酒与你 2020-12-03 07:30

When trying to compare software versions 5.12 to 5.8, version 5.12 is newer, however mathematically 5.12 is less than 5.8. How would I compare the two versions so that a new

16条回答
  •  佛祖请我去吃肉
    2020-12-03 08:30

    Here is what I did by modifying some code I found on StackOverflow and writing some myself. This is version 1 of the code so please let me know what you think. Usage examples and test cases are in the code comments.

    First create this function if not using SQL 2016 or greater and you do not have access to STRING_SPLIT:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:      
    -- Create date: 
    -- Description: modified from https://stackoverflow.com/questions/10914576/t-sql-split-string/42000063#42000063
    -- =============================================
    CREATE FUNCTION [dbo].[SplitStringToRows]
    (   
        @List VARCHAR(4000) 
        , @Delimiter VARCHAR(50)
    )
    RETURNS TABLE 
    AS
    RETURN 
    (
        --For testing
        -- SELECT * FROM SplitStringToRows ('1.0.123','.')
        -- DECLARE @List VARCHAR(MAX) = '1.0.123', @Delimiter VARCHAR(50) = '.';
    
        WITH Casted AS
        (
            SELECT CAST(N'' + REPLACE((SELECT REPLACE(@List,@Delimiter,N'§§Split$me$here§§') AS [*] FOR XML PATH('')),N'§§Split$me$here§§',N'') + N'' AS XML) AS SplitMe
        )
        SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS [Index]
        , x.value(N'.',N'nvarchar(max)') AS Part 
        FROM Casted
        CROSS APPLY SplitMe.nodes(N'/x') AS A(x)
    )
    

    Then create this function:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    -- =============================================
    -- Author:      Soenhay
    -- Create date: 7/1/2017
    -- Description: Returns -1 if VersionStringA is less than VersionStringB.
    --              Returns 0 if VersionStringA equals VersionStringB.
    --              Returns 1 if VersionSTringA is greater than VersionStringB.
    -- =============================================
    CREATE FUNCTION dbo.CompareVersionStrings
    (   
        @VersionStringA VARCHAR(50)
        ,@VersionStringB VARCHAR(50)
    )
    RETURNS TABLE 
    AS
    RETURN 
    (
        --CurrentVersion should be of the form:
        --major.minor[.build[.revision]] 
        --This is the same as the versioning system used in c#.
        --For applications the build and revision numbers will by dynamically set based on the current date and time of the build. 
        --Example: [assembly: AssemblyFileVersion("1.123.*")]//http://stackoverflow.com/questions/15505841/the-version-specified-for-the-file-version-is-not-in-the-normal-major-minor-b
        --Each component should be between 0 and 65534 ( UInt16.MaxValue - 1 )
        --Max version number would be 65534.65534.65534.65534
    
        --For Testing 
        -- SELECT * FROM dbo.CompareVersionStrings('', '')
        -- SELECT * FROM dbo.CompareVersionStrings('asdf.asdf', 'asdf.asdf') --returns 0
        -- SELECT * FROM dbo.CompareVersionStrings('asdf', 'fdas') --returns -1 
        -- SELECT * FROM dbo.CompareVersionStrings('zasdf', 'fdas') --returns 1 
        -- SELECT * FROM dbo.CompareVersionStrings('1.0.123.123', '1.1.123.123')  --Should return -1
        -- SELECT * FROM dbo.CompareVersionStrings('1.0.123.123', '1.0.123.123')  --Should return 0
        -- SELECT * FROM dbo.CompareVersionStrings('1.1.123.123', '1.0.123.123')  --Should return 1
        -- SELECT * FROM dbo.CompareVersionStrings('1.0.123.123', '1.0.124.123')  --Should return -1
        -- SELECT * FROM dbo.CompareVersionStrings('1.0.124.123', '1.0.123.123')  --Should return 1
        -- SELECT * FROM dbo.CompareVersionStrings('1.0.123.123', '1.0.123.124')  --Should return -1
        -- SELECT * FROM dbo.CompareVersionStrings('1.0.123.124', '1.0.123.123')  --Should return 1
        -- SELECT * FROM dbo.CompareVersionStrings('1.0', '1.1')  --Should return -1
        -- SELECT * FROM dbo.CompareVersionStrings('1.0', '1.0')  --Should return 0
        -- SELECT * FROM dbo.CompareVersionStrings('1.1', '1.0')  --Should return 1
        -- Declare @VersionStringA VARCHAR(50) = '' ,@VersionStringB VARCHAR(50) = '' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.0.123.123' ,@VersionStringB VARCHAR(50) = '1.1.123.123' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.1.123.123' ,@VersionStringB VARCHAR(50) = '1.1.123.123' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.2.123.123' ,@VersionStringB VARCHAR(50) = '1.1.123.123' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.1.123' ,@VersionStringB VARCHAR(50) = '1.1.123.123' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.1.123.123' ,@VersionStringB VARCHAR(50) = '1.1.123' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.1' ,@VersionStringB VARCHAR(50) = '1.1' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.2' ,@VersionStringB VARCHAR(50) = '1.1' ;
        -- Declare @VersionStringA VARCHAR(50) = '1.1' ,@VersionStringB VARCHAR(50) = '1.2' ;
    
        WITH 
        Indexes AS
        (
            SELECT 1 AS [Index]
                , 'major' AS Name
            UNION
            SELECT 2
                , 'minor'
            UNION
            SELECT 3
                , 'build'
            UNION
            SELECT 4
                , 'revision'
        )
        , SplitA AS
        (
            SELECT * FROM dbo.SplitStringToRows(@VersionStringA, '.')
        )
        , SplitB AS
        (
            SELECT * FROM dbo.SplitStringToRows(@VersionStringB, '.')
        )
        SELECT
            CASE WHEN major = 0 THEN
                    CASE WHEN minor = 0 THEN
                                        CASE WHEN build = 0 THEN
                                                            CASE WHEN revision = 0 THEN 0
                                                            ELSE revision END
                                            ELSE build END
                        ELSE minor END
                ELSE major END AS Compare
        FROM
        (
            SELECT 
                 MAX(CASE WHEN [Index] = 1 THEN Compare ELSE NULL END) AS major
                ,MAX(CASE WHEN [Index] = 2 THEN Compare ELSE NULL END) AS minor
                ,MAX(CASE WHEN [Index] = 3 THEN Compare ELSE NULL END) AS build
                ,MAX(CASE WHEN [Index] = 4 THEN Compare ELSE NULL END) AS revision
            FROM(
                SELECT [Index], Name, 
                    CASE WHEN A = B THEN 0
                        WHEN A < B THEN -1
                        WHEN A > B THEN 1
                        END AS Compare
                FROM
                (
                    SELECT 
                         i.[Index]
                        ,i.Name
                        ,ISNULL(a.Part, 0) AS A
                        ,ISNULL(b.Part, 0) AS B
                    FROM Indexes i
                        LEFT JOIN SplitA a
                    ON  a.[Index] = i.[Index]
                        LEFT JOIN SplitB b
                    ON  b.[Index] = i.[Index]
                ) q1
            ) q2
        ) q3
    
    )
    GO
    

提交回复
热议问题