如何使用SQL Server比较软件版本?

Ker*_*mit 15 sql t-sql sql-server

当尝试比较软件版本5.12到5.8时,版本5.12更新,但数学上5.12小于5.8.我如何比较两个版本,以便更新的版本返回'Y'?

SELECT CASE WHEN 5.12 > 5.8 THEN 'Y' ELSE 'N' END
Run Code Online (Sandbox Code Playgroud)

可能的解决方案

  1. 在5.8中的小数后添加一个0,以便它比较5.08到5.12,但似乎这需要一些代码.
  2. 只需比较小数点后的值(即12> 8),但是当版本滚动到6.0时,这会失败.
  3. 使用反向逻辑并假设如果5.12小于5.8则返回'Y'.我相信当版本滚动到6.0时这会失败.

Sea*_*ean 7

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
Run Code Online (Sandbox Code Playgroud)


Eva*_*acy 7

您可以hierarchyid 通过将 a/放在字符串的末尾和开头并进行转换来使用您可以使用的

例如

SELECT CASE WHEN cast('/5.12/' as hierarchyid) > cast('/5.8/' as hierarchyid) THEN 'Y' ELSE 'N' END

那返回一个 Y


aba*_*hev 6

我建议创建一个SQL CLR函数:

public partial class UserDefinedFunctions
{
    [SqlFunction(Name = "CompareVersion")] 
    public static bool CompareVersion(SqlString x, SqlString y)
    {
        return Version.Parse(x) > Version.Parse(y);
    }
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • SqlString具有显式强制转换为字符串.
  • 传递完整版本字符串 a.b.c.d


Ste*_*n C 5

这里有一个非常好的解决方案: 如何比较包含.NET System.Version类等版本号的SQL字符串?

在使用查询一段时间之后,我了解到当有4个或更多部分时它无法比较最后一部分(例如,如果版本号是1.2.3.4,它总是将最后一个视为0) .我已经修复了这个问题,并提出了另一个函数来比较两个版本号.

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
Run Code Online (Sandbox Code Playgroud)

用法/测试用例:

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
Run Code Online (Sandbox Code Playgroud)


Eri*_*ick 5

在尝试基于语义版本控制过滤SQL行时遇到了此问题。我的解决方案有所不同,因为我想存储带有语义版本号标记的配置行,然后选择与我们软件的运行版本兼容的行。

假设:

  • 我的软件将包含一个包含当前版本号的配置设置
  • 数据驱动的配置行将包含最小版本号
  • 我需要能够选择min <= current的配置行。

例子:

  • 1.0.0版本应包括:1.0.0、1.0.0-*,1.0.0-beta.1
  • 1.0.0版应排除:1.0.1、1.1.0、2.0.0
  • 1.1.0-beta.2版本应包括:1.0.0、1.0.1、1.1.0-beta1、1.1.0-beta.2
  • 1.1.0-beta.2版本应排除:1.1.0、1.1.1、1.2.0、2.0.0、1.1.1-beta.1

MSSQL UDF是:

CREATE FUNCTION [dbo].[SemanticVersion] (
    @Version nvarchar(50)
)
RETURNS nvarchar(255)

AS
BEGIN

    DECLARE @hyphen int = CHARINDEX('-', @version)
    SET @Version = REPLACE(@Version, '*', ' ')
    DECLARE 
        @left nvarchar(50) = CASE @hyphen WHEN 0 THEN @version ELSE SUBSTRING(@version, 1, @hyphen-1) END,
        @right nvarchar(50) = CASE @hyphen WHEN 0 THEN NULL ELSE SUBSTRING(@version, @hyphen+1, 50) END,
        @normalized nvarchar(255) = '',
        @buffer int = 8

    WHILE CHARINDEX('.', @left) > 0 BEGIN
        SET @normalized = @normalized + CASE ISNUMERIC(LEFT(@left, CHARINDEX('.', @left)-1))
            WHEN 0 THEN LEFT(@left, CHARINDEX('.', @left)-1)
            WHEN 1 THEN REPLACE(STR(LEFT(@left, CHARINDEX('.', @left)-1), @buffer), SPACE(1), '0')
        END  + '.'
        SET @left = SUBSTRING(@left, CHARINDEX('.', @left)+1, 50)
    END
    SET @normalized = @normalized + CASE ISNUMERIC(@left)
        WHEN 0 THEN @left
        WHEN 1 THEN REPLACE(STR(@left, @buffer), SPACE(1), '0')
    END

    SET @normalized = @normalized + '-'
    IF (@right IS NOT NULL) BEGIN
        WHILE CHARINDEX('.', @right) > 0 BEGIN
            SET @normalized = @normalized + CASE ISNUMERIC(LEFT(@right, CHARINDEX('.', @right)-1))
                WHEN 0 THEN LEFT(@right, CHARINDEX('.', @right)-1)
                WHEN 1 THEN REPLACE(STR(LEFT(@right, CHARINDEX('.', @right)-1), @buffer), SPACE(1), '0')
            END  + '.'
            SET @right = SUBSTRING(@right, CHARINDEX('.', @right)+1, 50)
        END
        SET @normalized = @normalized + CASE ISNUMERIC(@right)
            WHEN 0 THEN @right
            WHEN 1 THEN REPLACE(STR(@right, @buffer), SPACE(1), '0')
        END
    END ELSE 
        SET @normalized = @normalized + 'zzzzzzzzzz'

    RETURN @normalized

END
Run Code Online (Sandbox Code Playgroud)

SQL测试包括:

SELECT CASE WHEN dbo.SemanticVersion('1.0.0-alpha') < dbo.SemanticVersion('1.0.0-alpha.1') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.0-alpha.1') < dbo.SemanticVersion('1.0.0-alpha.beta') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.0-alpha.beta') < dbo.SemanticVersion('1.0.0-beta') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.0-beta') < dbo.SemanticVersion('1.0.0-beta.2') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.0-beta.2') < dbo.SemanticVersion('1.0.0-beta.11') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.0-beta.11') < dbo.SemanticVersion('1.0.0-rc.1') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.0-rc.1') < dbo.SemanticVersion('1.0.0') THEN 'Success' ELSE 'Failure' END


SELECT CASE WHEN dbo.SemanticVersion('1.0.0-*') <= dbo.SemanticVersion('1.0.0') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.*') <= dbo.SemanticVersion('1.0.0') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.*') <= dbo.SemanticVersion('1.0.0') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('*') <= dbo.SemanticVersion('1.0.0') THEN 'Success' ELSE 'Failure' END

SELECT CASE WHEN dbo.SemanticVersion('1.0.0-*') <= dbo.SemanticVersion('1.0.0') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.1-*') > dbo.SemanticVersion('1.0.0') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.0.1-*') <= dbo.SemanticVersion('1.0.1') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.1.*') > dbo.SemanticVersion('1.0.9') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.1.*') <= dbo.SemanticVersion('1.2.0') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.*') <= dbo.SemanticVersion('2.0.0') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('1.*') > dbo.SemanticVersion('0.9.9-beta-219') THEN 'Success' ELSE 'Failure' END
SELECT CASE WHEN dbo.SemanticVersion('*') <= dbo.SemanticVersion('0.0.1-alpha-1') THEN 'Success' ELSE 'Failure' END
Run Code Online (Sandbox Code Playgroud)