2012-07-06 60 views
12

當試圖比較軟件版本5.12到5.8時,版本5.12更新,但數學上5.12小於5.8。我如何比較這兩個版本,以便更新的版本返回'Y'?如何比較使用SQL Server的軟件版本?

SELECT CASE WHEN 5.12 > 5.8 THEN 'Y' ELSE 'N' END 

可能的解決方案

  1. 在5.8到小數點後添加一個0,使其比較5.08 5.12,但是好像這將需要一些代碼。
  2. 簡單地比較小數點後的值(即12> 8),但是當版本滾動到6.0時失敗。
  3. 使用反向邏輯並假設5.12小於5.8返回'Y'。我相信這個版本在6.0版本時會失敗。
+7

SQL Server的版本?如果2008+'DECLARE @ V1 VARCHAR(10)='5.12',@ V2 VARCHAR(10)='5.8'; CAST('/'+ @ V1 +'/'AS HIERARCHYID) '+ @ V2 +'/'AS HIERARCHYID)THEN'Y'ELSE'N'END' – 2013-12-18 16:30:19

+0

@MartinSmith你遲到了。 – Kermit 2013-12-18 19:28:35

回答

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 
+0

這可以根據需要輕鬆擴展到_n_部分版​​本號。 – DaveE 2013-07-19 19:59:00

4

兩個步驟,首先比較小數點左邊和之後比較右邊。


可能的解決辦法:

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, RIGHT(@v1, LEN(@v1) - CHARINDEX('.', @v1))) < CONVERT(int, RIGHT(@v2, LEN(@v2) - CHARINDEX('.', @v2))) then 'v2 is newer' 
    when CONVERT(int, RIGHT(@v1, LEN(@v1) - CHARINDEX('.', @v1))) > CONVERT(int, RIGHT(@v2, LEN(@v2) - CHARINDEX('.', @v2))) then 'v1 is newer' 
    else 'same!' end as 'Version Test' 
+0

當數據類型爲float時,當版本以'.0'結尾時不起作用。 – Kermit 2012-07-06 17:50:07

1

字符串中的究竟是不是一個字符串,不要存放。另一種方法是創建自己的數據類型(在C#中 - 允許一段時間),它們將版本存儲爲一系列字節並實現適當的比較邏輯。

+0

你能詳細說明你的意思嗎?「不要存儲在字符串中什麼不是字符串?」 – Kermit 2012-07-06 14:59:56

+0

簡單的5.12不是一個字符串 - 它是一個由2個數字組成的序列(5,12)。在varchar中對它們進行破解強制使用字符串語義 - 這是行不通的。將它們存儲在自定義類型中意味着您可以放入適當的語義。http://msdn.microsoft.com/en-us/library/ms131120.aspx有關於此的詳細信息。 – TomTom 2012-07-06 15:09:01

+0

也許我應該補充說我將這些存儲爲小數。 – Kermit 2012-07-06 15:11:56

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); 
    } 
} 

注:

  • 的SqlString具有explicit cast字符串。爲
  • 通完整的版本號a.b.c.d
1

正如AF建議你可以比較INT部分,然後從給出的所有答案的小數部分有一定的成果是利用PARSENAME。你做的另一種方式可以嘗試下TomTom的回答是這樣的

case when cast(@var as int)>cast(@var2 as int) then 'Y' 
when cast(PARSENAME(@var,1) as int) > cast(PARSENAME(@var2,1) as int) THEN 'Y' 


Declare @var float 
Declare @var2 float 
set @var=5.14 
set @var2=5.8 
Select case when cast(@var as int)>cast(@var2 as int) then 'Y' 
when cast(PARSENAME(@var,1) as int)> cast(PARSENAME(@var2,1) as int) THEN 'Y' 
else 'N' END 
+0

我不確定如果我沒有正確測試這個,但是當'@ var' = 5.14和'@ var2' = 5.8時它似乎失敗了。 – Kermit 2012-07-06 15:44:50

+0

我還沒有執行查詢,但您可以將parsename轉換爲int示例強制轉換(PARSENAME(@ var,1)作爲int。我更新了我的答案!! – praveen 2012-07-06 15:48:10

1

你不會在這個問題這麼說,但your comment建議你存儲的版本號爲[小數] [d]。我猜你有一個像這樣的表:

CREATE TABLE ReleaseHistory (
    VersionNumber DECIMAL(6,3) NOT NULL 
); 
GO 

INSERT INTO ReleaseHistory (
    VersionNumber 
) 
VALUES 
    (5.12), 
    (5.8), 
    (12.34), 
    (3.14), 
    (0.78), 
    (1.0); 
GO 

下面的查詢是排名由訂單的版本中,他們將被釋放的嘗試:

SELECT 
    VersionNumber, 
    RANK() OVER (ORDER BY VersionNumber) AS ReleaseOrder 
FROM ReleaseHistory; 

它產生以下結果集:

VersionNumber       ReleaseOrder 
--------------------------------------- -------------------- 
0.780         1 
1.000         2 
3.140         3 
5.120         4 
5.800         5 
12.340         6 

這不是我們所期望的。版本5.8在版本5.12之前發佈!

將版本號拆分爲主要和次要組件,以正確排列版本號。一種方法是將十進制值轉換爲字符串並在該句點上進行拆分。造成這種情況的T-SQL語法是醜陋的(語言並非設計用於字符串處理):

WITH VersionStrings AS (
    SELECT CAST(VersionNumber AS VARCHAR(6)) AS VersionString 
    FROM ReleaseHistory 
), 
VersionNumberComponents AS (
    SELECT 
    CAST(SUBSTRING(VersionString, 1, CHARINDEX('.', VersionString) - 1) AS INT) AS MajorVersionNumber, 
    CAST(SUBSTRING(VersionString, CHARINDEX('.', VersionString) + 1, LEN(VersionString) - CHARINDEX('.', VersionString)) AS INT) AS MinorVersionNumber 
    FROM VersionStrings 
) 
SELECT 
    CAST(MajorVersionNumber AS VARCHAR(3)) + '.' + CAST(MinorVersionNumber AS VARCHAR(3)) AS VersionString, 
    RANK() OVER (ORDER BY MajorVersionNumber, MinorVersionNumber) AS ReleaseOrder 
FROM VersionNumberComponents; 

但它提供了預期的結果:

VersionString ReleaseOrder 
------------- -------------------- 
0.780   1 
1.0   2 
3.140   3 
5.120   4 
5.800   5 
12.340  6 

由於Tomtom replied,小數點是不是一個好鍵入以存儲版本號。最好將版本號存儲在兩個正整數列中,一列包含主版本號,另一列包含次版本號。

+0

將當前版本號與行中的版本以小數形式存儲。 – Kermit 2012-07-07 02:42:33

1

這是基於SeanW的答案,但該解決方案允許以下格式[major]。[minor]。[build]。它可能用於SQL 2K,並且遊標不是選項。

declare @v1 varchar(100) = '1.4.020' 
declare @v2 varchar(100) = '1.4.003' 

declare @v1_dot1_pos smallint /*position - 1st version - 1st dot */ 
declare @v1_dot2_pos smallint /*position - 1st version - 2nd dot */ 
declare @v2_dot1_pos smallint /*position - 2nd version - 1st dot */ 
declare @v2_dot2_pos smallint /*position - 2nd version - 2nd dot */ 

------------------------------------------------- 
-- get the pos of the first and second dots 
------------------------------------------------- 
SELECT 
@v1_dot1_pos=CHARINDEX('.', @v1), 
@v2_dot1_pos=CHARINDEX('.', @v2), 
@v1_dot2_pos=charindex('.', @v1, charindex('.', @v1) + 1), 
@v2_dot2_pos=charindex('.', @v2, charindex('.', @v2) + 1) 


------------------------------------------------- 
-- break down the parts 
------------------------------------------------- 
DECLARE @v1_major int, @v2_major int 
DECLARE @v1_minor int, @v2_minor int 
DECLARE @v1_build int, @v2_build int 

SELECT 
    @v1_major = CONVERT(int,LEFT(@v1,@v1_dot1_pos-1)), 
    @v1_minor = CONVERT(int,SUBSTRING(@v1,@v1_dot1_pos+1,(@[email protected]_dot1_pos)-1)), 
    @v1_build = CONVERT(int,RIGHT(@v1,(LEN(@v1)[email protected]_dot2_pos))), 
    @v2_major = CONVERT(int,LEFT(@v2,@v2_dot1_pos-1)), 
    @v2_minor = CONVERT(int,SUBSTRING(@v2,@v2_dot1_pos+1,(@[email protected]_dot1_pos)-1)), 
    @v2_build = CONVERT(int,RIGHT(@v2,(LEN(@v2)[email protected]_dot2_pos))) 


------------------------------------------------- 
-- return the difference 
------------------------------------------------- 
SELECT 
    Case  
     WHEN @v1_major < @v2_major then 'v2 is newer' 
     WHEN @v1_major > @v2_major then 'v1 is newer' 
     WHEN @v1_minor < @v2_minor then 'v2 is newer' 
     WHEN @v1_minor > @v2_minor then 'v1 is newer' 
     WHEN @v1_build < @v2_build then 'v2 is newer' 
     WHEN @v1_build > @v2_build then 'v1 is newer' 
     ELSE '!Same' 
    END 
1

這是實現的解決方案:

CREATE FUNCTION [dbo].[version_compare] 
(
    @v1 VARCHAR(5), @v2 VARCHAR(5) 
) 
RETURNS tinyint 
AS 
BEGIN 
    DECLARE @v1_int tinyint, @v1_frc tinyint, 
      @v2_int tinyint, @v2_frc tinyint, 
      @ResultVar tinyint 

    SET @ResultVar = 0 

    SET @v1_int = CONVERT(tinyint, LEFT(@v1, CHARINDEX('.', @v1) - 1)) 
    SET @v1_frc = CONVERT(tinyint, RIGHT(@v1, LEN(@v1) - CHARINDEX('.', @v1))) 
    SET @v2_int = CONVERT(tinyint, LEFT(@v2, CHARINDEX('.', @v2) - 1)) 
    SET @v2_frc = CONVERT(tinyint, RIGHT(@v2, LEN(@v2) - CHARINDEX('.', @v2))) 

    SELECT @ResultVar = CASE 
     WHEN @v2_int > @v1_int THEN 2 
     WHEN @v1_int > @v2_int THEN 1 
     WHEN @v2_frc > @v1_frc THEN 2 
     WHEN @v1_frc > @v2_frc THEN 1 
    ELSE 0 END 

    -- Return the result of the function 
    RETURN @ResultVar 
END 
GO 
5

有從重複的問題在這裏一個很好的解決方案: How to compare SQL strings that hold version numbers like .NET System.Version class?

與查詢一會兒打後,我才知道,當有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 

用法/測試用例:

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 
0

你可以使用hierarchyid 你可以通過把一個/末和字符串的開始和鑄造它

例如使用

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

返回一個Y

2

試圖篩選基於SQL semantic versioning行,當我遇到了這一點。我的解決方案有點不同,因爲我想存儲標記有語義版本號的配置行,然後選擇與正在運行的軟件版本兼容的行。

假設:

  • 我的軟件將包括含有當前版本號
  • 數據驅動的配置行將包括最小版本號
  • 我需要能夠選擇配置行的配置設置其中最小< =當前。

實例:

  • 版本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-beta.1,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 

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 
0

這是我通過修改一些我在StackOverflow上找到的代碼和自己寫的代碼。這是代碼的第1版,請讓我知道您的想法。用法示例和測試用例在代碼註釋中。

首先創建這個功能,如果不使用SQL 2016或更高版本,你不訪問STRING_SPLIT:

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
-- ============================================= 
-- Author:  <Author,,Name> 
-- Create date: <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'<x>' + REPLACE((SELECT REPLACE(@List,@Delimiter,N'§§Split$me$here§§') AS [*] FOR XML PATH('')),N'§§Split$me$here§§',N'</x><x>') + N'</x>' 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) 
) 

然後建立這個功能:

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 
0

這遞歸查詢將轉換任何「 。'將版本號分離爲可比較的字符串,將每個元素左填充爲10個字符,從而允許比較帶有或不帶有內部版本號的版本,並適用於非數字字符:

WITH cte (VersionNumber) AS (
    SELECT '1.23.456' UNION ALL 
    SELECT '2.3'  UNION ALL 
    SELECT '0.alpha-3' 
), 
    parsed (VersionNumber, Padded) AS (
    SELECT 
    CAST(SUBSTRING(VersionNumber, CHARINDEX('.', VersionNumber) + 1, LEN(VersionNumber)) + '.' AS NVARCHAR(MAX)), 
    CAST(RIGHT(REPLICATE('0', 10) + LEFT(VersionNumber, CHARINDEX('.', VersionNumber) - 1), 10) AS NVARCHAR(MAX)) 
    FROM cte 
    UNION ALL 
    SELECT 
    SUBSTRING(VersionNumber, CHARINDEX('.', VersionNumber) + 1, LEN(VersionNumber)), 
    Padded + RIGHT(REPLICATE('0', 10) + LEFT(VersionNumber, CHARINDEX('.', VersionNumber) - 1), 10) 
    FROM parsed WHERE CHARINDEX('.', VersionNumber) > 0 
) 
SELECT Padded 
FROM parsed 
WHERE VersionNumber = '' 
ORDER BY Padded; 

Padded 
------------------------------ 
0000000000000alpha-3 
000000000100000000230000000456 
00000000020000000003