21

ソフトウェア バージョン 5.12 と 5.8 を比較すると、バージョン 5.12 の方が新しいですが、数学的には 5.12 は 5.8 よりも小さいです。新しいバージョンが「Y」を返すように、2 つのバージョンを比較するにはどうすればよいですか?

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

可能な解決策

  1. 5.08 と 5.12 を比較するために、5.8 の小数点の後に 0 を追加しますが、これには少しコードが必要になるようです。
  2. 小数点以下の値を単純に比較します (つまり、12 > 8)。ただし、バージョンが 6.0 になると失敗します。
  3. 逆の論理を使用し、5.12 が 5.8 未満の場合は「Y」を返すと想定します。バージョンが 6.0 になると、これは失敗すると思います。
4

18 に答える 18

8
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
于 2012-07-06T14:38:23.520 に答える
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 には、文字列への明示的なキャストがあります。
  • 現在の完全なバージョン文字列を渡すa.b.c.d
于 2012-07-06T14:41:45.440 に答える
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-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
于 2017-05-08T20:38:51.303 に答える
4

2段階、最初に小数点の左側を比較し、次に右側を比較します。


考えられる解決策:

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'
于 2012-07-06T14:36:12.993 に答える
2

文字列でないものを文字列に格納しないでください。別の方法は、バージョンを一連のバイトとして格納し、適切な比較ロジックを実装する独自のデータ型を作成することです (C# では、しばらくの間許可されます)。

于 2012-07-06T14:41:28.170 に答える
2

AFで示唆されているように、int部分と小数部分を比較できます。与えられたすべての回答とは別に、 parsename を使用してそれを行う方法がもう1つあります。このようなことを試すことができます

 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
于 2012-07-06T14:50:24.427 に答える
1

これはSeanWの回答に基づいていますが、このソリューションでは次の形式[メジャー]。[マイナー]。[ビルド]が可能です。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,(@v1_dot2_pos-@v1_dot1_pos)-1)),
    @v1_build = CONVERT(int,RIGHT(@v1,(LEN(@v1)-@v1_dot2_pos))),
    @v2_major = CONVERT(int,LEFT(@v2,@v2_dot1_pos-1)),
    @v2_minor = CONVERT(int,SUBSTRING(@v2,@v2_dot1_pos+1,(@v2_dot2_pos-@v2_dot1_pos)-1)),
    @v2_build = CONVERT(int,RIGHT(@v2,(LEN(@v2)-@v2_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
于 2013-02-24T08:40:38.030 に答える
1

質問ではそうは言っていませんが、トムトムの回答の下にあるコメントは、バージョン番号を [decimals][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 の前にリリースされました!

バージョン番号をメジャー コンポーネントとマイナー コンポーネントに分割して、バージョン番号を適切にランク付けします。これを行う 1 つの方法は、10 進数値を文字列に変換し、ピリオドで分割することです。このための 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 が答えたように、10 進数はバージョン番号を格納するのに適した型ではありません。バージョン番号を 2 つの正の整数列に格納することをお勧めします。1 つはメジャー バージョン番号を含み、もう 1 つはマイナー バージョン番号を含みます。

于 2012-07-06T21:47:53.383 に答える