2012-07-06 16 views
12

Al intentar comparar las versiones de software 5.12 a 5.8, la versión 5.12 es más nueva, sin embargo matemáticamente 5.12 es menor que 5.8. ¿Cómo compararía las dos versiones para que una versión más reciente devuelva 'Y'?¿Cómo comparar versiones de software usando SQL Server?

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

Soluciones Posibles

  1. Añadir un 0 después del decimal en el 5,8 por lo que se compara 05.08 a 05.12, sin embargo parece que esto requeriría un poco de código.
  2. Simplemente compare los valores después del decimal (es decir, 12> 8), sin embargo, esto falla cuando la versión pasa a 6.0.
  3. Utilice la lógica inversa y suponga que si 5.12 es menor que 5.8 para devolver 'Y'. Creo que esto fallaría cuando la versión llegue a 6.0.
+7

versión de SQL Server? Si 2008+ 'DECLARE @ V1 VARCHAR (10) = '5.12', @ V2 VARCHAR (10) = '5.8'; SELECCIONE CASO CUANDO CAST ('/' + @ V1 + '/' AS HIERARCHYID)> CAST ('/ '+ @ V2 +'/'AS HIERARCHYID) ENTONCES' Y 'ELSE' N 'END' –

+0

@MartinSmith Llegas tarde. – Kermit

Respuesta

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

Y esto se puede extender fácilmente a los números de versión _n_-parte según sea necesario. – DaveE

4

Dos pasos, primero compare el lado izquierdo del punto decimal y luego compare el derecho.


Posible solución:

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

Cuando el tipo de datos es flotante, no funciona cuando la versión termina en '.0'. – Kermit

1

No almacenar en una cadena que no es una cadena. La alternativa es crear su propio tipo de datos (en C# - permitido por algún tiempo) que almacena las versiones como una secuencia de bytes e implementa la lógica de comparación adecuada.

+0

¿Puedes elaborar lo que quieres decir con "No almacenar en una cadena lo que no es una cadena?" – Kermit

+0

Simple 5.12 NO ES UNA CADENA: es una secuencia de 2 números (5, 12). Apilarlos en un varchar está forzando la semántica de cadenas en eso, lo que no funciona. Almacenarlos en un tipo personalizado significa que puede poner la semántica adecuada. Http://msdn.microsoft.com/en-us/library/ms131120.aspx tiene detalles al respecto. – TomTom

+0

Quizás debería haber agregado que estoy almacenando estos como decimales. – Kermit

6

recomiendo para crear una función de SQL CLR:

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

Notas:

  • SqlString tiene explicit cast a cadena.
  • Pass cadena de la versión completa como de a.b.c.d
1

Según lo sugerido por la FA puede comparar la parte int y luego la parte decimal .Apart de todas las respuestas dadas Hay otra manera de hacerlo utilizando .tiene ParseName podría intentar algo como esto

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

No estoy seguro de si no estoy probando esto correctamente, pero parece fallar cuando '@ var' = 5.14 y' @ var2' = 5.8. – Kermit

+0

No he ejecutado la consulta, pero puede convertir parsename a int example cast (PARSENAME (@ var, 1) como int. He actualizado mi respuesta! – praveen

1

no lo dice en la pregunta, pero la respuesta de your comment bajo Tomtom sugiere que está almacenando los números de versión como [decimales] [d]. Supongo que usted tiene una tabla como la siguiente:

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 

La siguiente consulta es un intento para clasificar versiones por el orden en que serían liberados:

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

Se produce el siguiente conjunto de resultados:

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

Esto no es lo que esperamos. ¡La versión 5.8 fue lanzada antes de la versión 5.12!

Divida el número de versión en sus componentes principal y secundario para clasificar los números de versión correctamente.Una forma de hacerlo es convertir el valor decimal en una cadena y dividir en el período. La sintaxis de T-SQL para esto es fea (la lengua no está diseñado para el procesamiento de cadenas):

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; 

sino que proporciona el resultado esperado:

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

Como Tomtom replied, decimal a no es un buen escriba para almacenar un número de versión. Sería mejor almacenar el número de versión en dos columnas enteras positivas, una que contiene el número de versión principal y la otra que contiene el número de versión menor.

+0

El número de versión actual se comparó con la versión en una fila, que fue almacenado como un decimal. – Kermit

1

Esto se basa en la respuesta de SeanW, pero esta solución permite el siguiente formato [mayor]. [Menor]. [Compilación]. Puede usarse para SQL 2K y cuando el cursor no es una opción.

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

La solución que se implementó:

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

Hubo una muy buena solución a partir de una pregunta duplicado aquí: How to compare SQL strings that hold version numbers like .NET System.Version class?

Después de jugar con la consulta por un tiempo, supe que no fue posible comparar la última parte cuando hay 4 o más partes (por ejemplo, si el número de versión era 1.2.3.4, siempre trataría el último como 0). He solucionado ese problema y se me ocurrió otra función para comparar dos números de versión.

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 

caso de uso/Test:

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

usted podría utilizar hierarchyid que se puede utilizar por poner un / en el final y el inicio de la cadena y echándola

por ejemplo,

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

que devuelve un Y

2

me encontré con esto cuando se trata de filtrar filas SQL basado en semantic versioning. Mi solución fue un poco diferente, en el sentido de que quería almacenar filas de configuración etiquetadas con un número de versión semántica y luego seleccionar filas compatibles con una versión en ejecución de nuestro software.

Supuestos:

  • Mi software incluirá una opción de configuración que contiene el número de versión actual
  • filas de configuración basadas en datos incluirá un número de versión min
  • tengo que ser capaz de seleccionar las filas de configuración donde min < = actual.

Ejemplos:

  • Versión 1.0.0 debería incluir: 1.0.0, 1.0.0- *, 1.0.0-beta.1
  • Versión 1.0.0 deben excluir: 1,0. 1, 1.1.0, 2.0.0
  • La versión 1.1.0-beta.2 debe incluir: 1.0.0, 1.0.1, 1.1.0-beta.1, 1.1.0-beta.2
  • Versión 1.1.0-beta.2 debe excluir: 1.1.0, 1.1.1, 1.2.0, 2.0.0, 1.1.1-beta.1

El MSSQL UDF es:

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 

pruebas SQL incluyen:

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

Esto es lo que hice modificando algunos código que encontré en StackOverflow y escribí uno yo mismo. Esta es la versión 1 del código, por favor déjame saber lo que piensas. Ejemplos de uso y casos de prueba están en los comentarios del código.

En primer lugar crear esta función si no se usa SQL 2016 o más y que no tienen acceso a 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) 
) 

A continuación, cree esta función:

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

Esta consulta recursiva sería convertir cualquier ' .'- separaron los números de versión en cadenas comparables con el margen izquierdo de cada elemento a 10 caracteres, lo que permite comparar versiones con o sin número de compilación y acomodar caracteres no numéricos:

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 
Cuestiones relacionadas