¿Existe una clasificación para ordenar las siguientes cadenas en el siguiente orden 1,2,3,6,10,10A, 10B, 11?


12

Tengo una base de datos con una columna VARCHAR que contiene enteros de longitud variable. Quiero ordenarlos para que 10 venga después de 9, no 1, y 70A venga después de 70. Pude hacer esto con PATINDEX () , un CTE y declaraciones CASE en la cláusula WHERE.

Sin embargo, me preguntaba si había una recopilación donde esto sería innecesario.


Aquí está el nuevo enlace para esa sugerencia ahora que Microsoft ha migrado de Connect a UserVoice pero no ha reenviado los URI: admite "clasificación natural" / DIGITSASNUMBERS como una opción de colación
Solomon Rutzky

2
Microsoft ha dicho que implementarán esto como una característica incorporada en SQL Server si obtienen suficientes votos. Así que ve aquí y haz clic en el botón de votar .
Peter Aylett

Respuestas:


8

No. La clasificación se trata de la clasificación alfabética, según la página de códigos, el acento, el caso, el ancho, el kana. Los caracteres de números (0-9) no tienen ninguna de sus propiedades.

Por 9lo tanto, siempre es después 10Bde cualquier tipo.

Tienes que dividirlo como has notado o ordenar de esta manera:

ORDER BY
    RIGHT('                              ' + MyColumn, 30)

La longitud a la derecha determina cuántos espacios tienes.

Por supuesto que podrías:

  • tener 2 columnas para hacer esto innecesario (y mucho más rápido) y tener una columna calculada para combinarlas
  • insistir en ceros a la izquierda
  • justificar a la derecha en un char (una versión almacenada de mi DERECHA anterior)

Las últimas 2 sugerencias son como mi DERECHA anterior y ligeramente diferentes. Más rápido de clasificar (no se necesita procesar el colukmn) pero se requiere más almacenamiento


No veo cómo funciona esto. Se rompe por 2, 2a, 3, etc ...
Mladen Prajdic

@Mladen Prajdic: tienes razón, oops. Olvidé los alfabéticos finales
gbn

Con respecto a " So 9is after after 10Bin any sort. ": Es solo así en SQL Server porque la opción de clasificación subyacente para manejar "DigitsAsNumbers" no se ha expuesto como una opción de Intercalación. Todavía ;-). Esto se hizo disponible para aplicaciones basadas en Windows a partir de Windows 7, especialmente en el Explorador de archivos. Y un día puede estar expuesto a SQL Server, si suficientes personas apoyan la idea. Traté de hacer que la pelota rodara presentando la siguiente sugerencia de Connect: admite "clasificación natural" / DIGITSASNUMBERS como una opción de clasificación .
Solomon Rutzky

8

Configuraría una columna calculada y luego ordenaría según eso. Algo como

CAST( 
     CASE WHEN IS_NUMERIC(left(OtherColumn, 2) = 1) then 
         left(OtherColumn,2) 
     else 
         left(otherColumn, 1)  
AS INT)

Luego use esta columna para ordenar, ya que ahora puede indexar la columna.


Es realmente útil saber sobre problemas similares. Sin embargo, en este caso no puedo cambiar el esquema.
Justin Dearing

¿Puedes agregar al esquema? Salvo una columna calculada, siempre puede crear una vista, aunque esto no será realmente optimizable como podría ser una columna calculada.
Aaron Bertrand

Si realiza una vista indizada y tiene la edición Enterprise, su consulta utilizará la vista indizada automáticamente si puede descubrir qué está tratando de hacer. Si fuera una edición estándar, necesitaría utilizar WITH (NOEXPAND) para activar la vista indizada que se utilizará. En ese punto, necesitaría tener la declaración del caso en su pedido, pero creo que debería funcionar.
mrdenny

No necesita crear una columna calculada. Puede usar esa expresión directamente en la cláusula ORDER BY
a_horse_with_no_name

Si desea garantizar un índice o exploración de tabla, puede hacerlo. Si desea poder indexar el valor, se necesita una columna calculada o una vista indexada.
mrdenny

5

Si desea una forma dolorosa de demostrar lo que dice @gbn (esencialmente que no puede distinguir una clasificación para ordenar subcadenas de manera diferente), puede hacer una tabla rápida #temp que tenga un coeficiente para el orden que espera, y ver si ordenar por cualquier colación devuelve el mismo orden:

CREATE TABLE #foo(id INT, n NVARCHAR(10));

CREATE TABLE #bar(collation SYSNAME);

SET NOCOUNT ON;

INSERT #foo SELECT 1,'1'
UNION SELECT 2,'2'
UNION SELECT 3,'3'
UNION SELECT 4,'6'
UNION SELECT 5,'10'
UNION SELECT 6,'10A'
UNION SELECT 7,'10B'
UNION SELECT 8,'11';

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'
    WITH x AS 
    (
        SELECT n, rn = ROW_NUMBER() OVER 
        (ORDER BY n COLLATE ' + name + ') FROM #foo
    ) 
    INSERT #bar 
    SELECT TOP (1) ''' + name + ''' FROM x
    WHERE NOT EXISTS
    (
        SELECT COUNT(*) FROM #foo AS f
        WHERE f.id = x.rn
        AND f.n <> x.n
    );' FROM sys.fn_helpcollations();

EXEC sp_executesql @sql;

SELECT collation FROM #bar;

GO
DROP TABLE #foo, #bar;

Esto funciona para mí en aproximadamente 10 segundos y produce 0 filas, lo que significa que no hay clasificación disponible para SQL Server (al menos 2008 R2, no he probado Denali) se ordenará de la manera que espera. Necesita una forma diferente de definir la ordenación.


2

¿Desea un medio sensato y eficiente para clasificar los números en cadenas como números reales? Considere votar por mi sugerencia de Microsoft Connect: soporte "clasificación natural" / DIGITSASNUMBERS como una opción de clasificación


Si bien esta pregunta es específica de SQL Server, y esta respuesta no lo es, sentí que aún debería publicar esta información simplemente para dar a conocer y no oponerme a ninguna de las otras respuestas.

Dicho esto, fuera de SQL Server, en ciertos entornos es posible hacer este tipo de clasificación. Es algo que al menos se especifica en la documentación de Unicode. En el LENGUAJE DE MARCADO DE DATOS LOCALES UNICODE (LDML) PARTE 5: estándar / informe COLLATION , hay un gráfico para la Configuración de clasificación que describe varias opciones para adaptar el comportamiento de clasificación. Una de las opciones es -kn-trueo [numericOrdering on]:

Si se establece en en , cualquier secuencia de dígitos decimales (General_Category = Nd en el [ UAX44 ]) se ordena a un nivel primario con su valor numérico. Por ejemplo, "A-21" <"A-123". Los pesos primarios calculados están todos al comienzo del grupo de reordenación de dígitos . Así, con una tabla UCA no adaptada, "a $" <"a0" <"a2" <"a12" <"a⓪" <"aa".

Sin embargo, este documento es un "estándar técnico" y no forma parte de la especificación central de Unicode. Una nota en la parte superior del documento dice:

Un estándar técnico Unicode (UTS) es una especificación independiente. La conformidad con el estándar Unicode no implica la conformidad con ningún UTS.

Por lo tanto, este comportamiento particular no está disponible en SQL Server o incluso en .NET (al menos no de forma nativa), aunque ambos se ajustan a la especificación central de Unicode.

El proyecto ICU (International Components for Unicode) es un conjunto de bibliotecas C / C ++ y Java que implementa esta funcionalidad, e incluso hay una demostración en línea de la misma. Y bajo "proyectos relacionados" hay un enlace a un proyecto .NET que parece ser un contenedor de objetos COM para la biblioteca ICU que permitiría que esta funcionalidad se exponga al código administrado. Pero no está claro si ese proyecto .NET aún está activo.

Pero para ver este comportamiento en acción, vaya a la demostración de colación de UCI .

Pegue lo siguiente en el área de texto de entrada en el lado izquierdo:

1
2
10B
6
11
10A
3
10

Establezca todas las opciones en "predeterminado". Marque la opción "ingresar números de línea" a la derecha del sortbotón y asegúrese de que la opción "intensidades de diferencia" no esté marcada.

Haga clic en el sortbotón y debería recuperar lo siguiente:

[1] 1
[8] 10
[6] 10A
[3] 10B
[5] 11
[2] 2
[7] 3
[4] 6

Esto es lo que se debe esperar al hacer una ordenación de cadena típica y lo que está viendo en SQL Server.

Ahora, en la serie de botones de radio justo encima del sortbotón, la segunda fila está etiquetada como "numérica". Seleccione el botón de opción "encendido".

Vuelva a hacer clic en el sortbotón y debería recuperar lo siguiente:

[1] 1
[2] 2
[7] 3
[4] 6
[8] 10
[6] 10A
[3] 10B
[5] 11

¿Se pregunta si esto funciona cuando la porción numérica está en el medio de la cadena? Ok, pegue lo siguiente en el área de texto de entrada en el lado izquierdo (reemplazando la lista anterior):

Script - 1.sql
Script - 2.sql
Script - 10B.sql
Script - 6.sql
Script - 11.sql
Script - 10A.sql
Script - 3.sql
Script - 10.sql

Asegúrese de que la configuración numérica todavía esté establecida en "on". Vuelva a hacer clic en el sortbotón y debería recuperar lo siguiente:

[1] Script - 1.sql
[2] Script - 2.sql
[7] Script - 3.sql
[4] Script - 6.sql
[8] Script - 10.sql
[6] Script - 10A.sql
[3] Script - 10B.sql
[5] Script - 11.sql

¿Quieres ver esto en otro lugar? Cree una carpeta en su disco duro, algo así como C: \ temp \ sorting \ , y cree archivos vacíos con los mismos nombres "Script -...". Haga una DIRen una ventana de comandos y verá la clasificación estándar. Pero al mirar la lista de archivos en el Explorador de Windows, verá la lista ordenada con la opción "numérica" ​​:-).


Para su información, Postgres 10 gana soporte para colaciones de UCI. Ver esta publicación de blog de Peter Eisentraut.
Basil Bourque

@BasilBourque Gracias por mencionar eso sobre PG10. Esa publicación de blog, al final, establece que "ICU ofrece una gran cantidad de funcionalidades en esta área que aún no estamos exponiendo a través de PostgreSQL. Hay opciones para la clasificación sin distinción entre mayúsculas y minúsculas, la clasificación sin distinción de acento y la personalización total de una recopilación". para aquellos en futuras versiones de PostgreSQL ". Entonces, en su primera / actual implementación, no cambia ninguna de la información en mi respuesta. Si una oferta futura permite la ordenación numérica, entonces lo mencionaré en mi respuesta, pero como una nota al pie ya que esta pregunta es específica de SQL Server.
Solomon Rutzky
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.