2010-08-13 17 views
11

Me pregunto si los genios SQL entre nosotros podrían echarnos una mano.Cómo puedo ordenar una columna de 'Número de versión' genéricamente usando una consulta de SQL Server

tengo una columna en una tabla VersionNoVersions que contiene los valores de los números de versión "como

VersionNo 
--------- 
1.2.3.1 
1.10.3.1 
1.4.7.2 

etc.

Busco para solucionar esto, pero, por desgracia, cuando hago un estándar order by , se trata como una cadena, por lo que el fin sale como

VersionNo 
--------- 
1.10.3.1 
1.2.3.1 
1.4.7.2 

Intead de los siguientes, que es wha t yo después:

VersionNo 
--------- 
1.2.3.1 
1.4.7.2 
1.10.3.1 

Por lo tanto, lo que tengo que hacer es ordenar los números en orden inverso (por ejemplo, en a.b.c.d, necesito ordenar por d, c, b, a para obtener la respuesta correcta).

Pero estoy atascado en cuanto a cómo lograr esto de una manera GENÉRICA. Claro, puedo dividir la cadena utilizando varias funciones sql (por ejemplo, left, right, substring, len, charindex), pero no puedo garantizar que siempre haya 4 partes para el número de versión. Puedo tener una lista como esta:

VersionNo 
--------- 
1.2.3.1 
1.3 
1.4.7.2 
1.7.1 
1.10.3.1 
1.16.8.0.1 

Can, ¿alguien tiene alguna sugerencia? Su ayuda sería muy apreciada.

+0

En este último caso , ¿cómo lo quiere ordenado dado que no tiene 4 cosas para ordenar? – gbn

+0

Como parece. Ese es mi problema, si se solucionara sería una brisa. –

Respuesta

18

Si está utilizando SQL Server 2008

select VersionNo from Versions order by cast('/' + replace(VersionNo , '.', '/') + '/' as hierarchyid); 

What is hierarchyid

Editar:

Soluciones para 2000, 2005, 2008: Solutions to T-SQL Sorting Challenge here.

The challenge

+0

Sería eso. Pero estoy atascado con el viejo SQL 2000, desafortunadamente. –

+0

@James Wiseman: En el enlace debe encontrar la solución para usted. –

+0

Brillante! Gracias por la ayuda. Lo intenté y funciona. –

0

Si puede, modifique el esquema para que la versión tenga 4 columnas en lugar de una. Entonces ordenar es fácil.

+0

Jaja, sí, eso se me ocurrió, desafortunadamente, esa no es una opción. Además, la longitud puede ser variable, y no puedo garantizar que la cantidad máxima de columnas sea 4, o cualquier otra cosa, realmente. –

+0

Si está usando SQL Server 2005 (puede ser 2008, necesita verificarlo dos veces) o más reciente, puede escribir un método .NET CLR para hacer la comparación, o mejor aún, transformar un número de versión arbitrario en un canónico, ordenable formato (por ejemplo, rellenar cada parte con, digamos, 5 dígitos); registre este método CLR con su base de datos y puede llamarlo como una función SQL normal. De lo contrario, tiene que implementar lo mismo en SQL, lo que probablemente sea malo para su rendimiento. – tdammers

+0

Sí, desafortunadamente es una vieja aplicación interna en VB6 y SQL 2000. –

3

En función de motor de SQL para MySQL sería algo como esto:

SELECT versionNo FROM Versions 
ORDER BY 
SUBSTRING_INDEX(versionNo, '.', 1) + 0, 
SUBSTRING_INDEX(SUBSTRING_INDEX(versionNo, '.', -3), '.', 1) + 0, 
SUBSTRING_INDEX(SUBSTRING_INDEX(versionNo, '.', -2), '.', 1) + 0, 
SUBSTRING_INDEX(versionNo, '.', -1) + 0;

Para MySQL versión 3.23.15 una por encima de

 
SELECT versionNo FROM Versions ORDER BY INET_ATON(ip); 
+0

Su SQL Server como la etiqueta indica, pero he actualizado mi pregunta en consecuencia. –

+0

Finalmente una solución que funciona, ¡gracias! Tenga en cuenta que 'INET_ATON' no funciona bien si los números no están todos por debajo de 256. – Paul

1

Otra manera de hacerlo:

Suponiendo que sólo tiene a, b, c, d Sólo usted puede también separar los datos a las columnas y hacer un pedido por a, b, c, d (todos desc) y obtener la fila 1 superior

Si necesita escalar a más de d para decir e, f, g ...basta con cambiar 1,2,3,4, a 1,2,3,4,5,6,7 y así sucesivamente en la consulta

Consulta: see demo

create table t (versionnumber varchar(255)) 
insert into t values 
('1.0.0.505') 
,('1.0.0.506') 
,('1.0.0.507') 
,('1.0.0.508') 
,('1.0.0.509') 
,('1.0.1.2') 


; with cte as 
(
    select 
    column1=row_number() over (order by (select NULL)) , 
    column2=versionnumber 
    from t 
    ) 

select top 1 
    CONCAT([1],'.',[2],'.',[3],'.',[4]) 
from 
(
    select 
     t.column1, 
     split_values=SUBSTRING(t.column2, t1.N, ISNULL(NULLIF(CHARINDEX('.',t.column2,t1.N),0)-t1.N,8000)), 
     r= row_number() over(partition by column1 order by t1.N) 
    from cte t 
     join 
     (
      select 
       t.column2, 
       1 as N 
      from cte t 
       UNION ALL 
      select 
       t.column2, 
       t1.N + 1 as N 
      from cte t 
       join 
       (
       select 
        top 8000 
         row_number() over(order by (select NULL)) as N 
       from 
        sys.objects s1 
         cross join 
        sys.objects s2 
       ) t1 
      on SUBSTRING(t.column2,t1.N,1) = '.' 
     ) t1 
      on t1.column2=t.column2 
)a 
pivot 
( 
    max(split_values) for r in ([1],[2],[3],[4]) 
    )p 
    order by [1] desc,[2] desc,[3] desc,[4] desc 
Cuestiones relacionadas