2010-09-27 11 views
12

En un caso de prueba que he escrito, la comparación de cadenas no parece funcionar de la misma manera entre SQL Server/.NET CLR.String Comparación de diferencias entre .NET y T-SQL?

Este código C#:

string lesser = "SR2-A1-10-90"; 
string greater = "SR2-A1-100-10"; 

Debug.WriteLine(string.Compare("A","B")); 
Debug.WriteLine(string.Compare(lesser, greater)); 

seria:

-1 
1 

Este código SQL Server:

declare @lesser varchar(20); 
declare @greater varchar(20); 

set @lesser = 'SR2-A1-10-90'; 
set @greater = 'SR2-A1-100-10'; 

IF @lesser < @greater 
    SELECT 'Less Than'; 
ELSE 
    SELECT 'Greater than'; 

seria:

Less Than 

¿Por qué la diferencia?

+0

¿Eres responsable de la distinción entre mayúsculas y minúsculas? –

+0

Los casos son iguales. La diferencia es cómo cada uno trata el '0' a '-'. –

+0

Esto es un problema Unicode, creo. Editar: Quizás no. Para mí, el código de SQL Server devuelve 'Greater than'. ¿Cuál es la intercalación predeterminada en la base de datos en la que lo está probando? –

Respuesta

10

Esto es documented here.

Las intercalaciones de Windows (por ejemplo, Latin1_General_CI_AS) usan reglas de intercalación de tipo Unicode. Las intercalaciones de SQL no.

Esto hace que el carácter de guión se trate de manera diferente entre los dos.

+0

seleccionar * de fn_helpcollations() donde nombre como '% SQL_Latin1_General_CP1_CI_AS%' o nombre – gbn

+0

La especie no Unicode = '' Latin1_General_CI_AS es diferente, utiliza CP 1252. Estoy seguro de LATIN1 .. hizo lo mismo también ... no, no ... http://msdn.microsoft.com/en-us/library/ms143515.aspx – gbn

3
  • En SQL que utiliza varchar que es básicamente ASCII (sujeto a colación) que dará - antes de 0
  • En C# todas las cadenas son Unicode

Los puntos más finos de UTF-xx (C#) vs UCS-2 (SQL Server) son bastante difíciles.

Editar:

he publicado demasiado pronto

me sale "mayor que" en SQL Server 2008 con Latin1_General_CI_AS intercalación

Edición 2:

también me gustaría probar en su SELECT ASCII(...) guión. Por ejemplo, si el fragmento de SQL ha estado alguna vez en un documento de Word, el - (150) no es el - (45) copié en SQL Server para probar mi navegador de sus preguntas. Consulte CP 1252 (= CP1 = lingo de SQL Server)

Edición 3: Vea la respuesta de Martin Smith: las 2 colaciones tienen diferentes órdenes de clasificación.

+0

Ah, ya veo. Cuando uso nvarchar (20), obtengo 'Greater Than'. –

+0

Lo consigo con varchar. ¿Su colación de DB es diferente a la intercalación de Servidor? – gbn

7

Además de la respuesta de gbn, puede hacer que se comporten de la misma manera utilizando CompareOptions.StringSort en C# (o usando StringComparison.Ordinal). Esto trata los símbolos que ocurren antes de los símbolos alfanuméricos, así que "-" < "0".

Sin embargo, Unicode vs ASCII no explica nada, ya que los códigos hexadecimales para la página de códigos ASCII se traducen literalmente a la página de códigos Unicode: "-" es 002D (45) mientras que "0" es 0030 (48).

Lo que está sucediendo es que .NET está utilizando la clasificación "lingüística" de forma predeterminada, que se basa en un orden no ordinario y el peso aplicado a varios símbolos por la cultura especificada o actual. Este algoritmo lingüístico permite, por ejemplo, "currículum" (deletreado con acentos) aparecer inmediatamente después de "reanudar" (deletreado sin acentos) en una lista ordenada de palabras, ya que "é" recibe un orden fraccionario justo después de "e" y mucho antes de "f". También permite que la "cooperación" y la "cooperación" se coloquen juntas, dado que el símbolo del tablero tiene un bajo "peso"; solo importa como desempate final absoluto cuando se ordenan palabras como "bits", "bit" y "bit-shift" (que aparecerían en ese orden).

La llamada clasificación ordinal (estrictamente según los valores Unicode, con o sin insensibilidad de mayúsculas y minúsculas) producirá resultados muy diferentes ya veces ilógicos, ya que las variantes de letras suelen aparecer bastante después del alfabeto latino básico sin decorar en ordinales ASCII/Unicode. mientras que los símbolos ocurren antes que él. Por ejemplo, "é" viene después de "z" y entonces las palabras "currículum", "colofón", "rublo", "currículum vitae" se ordenarán en ese orden. "Bit's", "Bit-shift", "Biter", "Bits" se ordenarán en ese orden cuando el apóstrofo llegue primero, seguido por el guión, luego la letra "e", luego la letra "s". Ninguno de estos parece lógico desde una perspectiva de "lenguaje natural".

+0

La página de códigos solo afecta a los caracteres> 127, ¿no? – gbn

+0

Cool. Al usar 'CompareOption.StringSort', puedo ejecutar mi prueba, con la configuración de intercalación de la base de datos actual. –

+0

@gbn - Técnicamente sí. También es C# que parece estar clasificando "mal"; sin StringSort, los símbolos de los caracteres aparecen después de los alfanuméricos. Voy a editar – KeithS

0

Ya hay varias respuestas excelentes sobre por qué sucede esto, pero estoy seguro de que otras solo quieren saber el código C# para iterar la colección en el mismo orden que el servidor SQL. He encontrado que lo siguiente funciona mejor. "Ordinal" soluciona el problema del guión, mientras que "IgnoreCase" parece reflejar también el valor predeterminado del servidor SQL.

Debug.WriteLine(string.Compare(lesser, greater, StringComparison.OrdinalIgnoreCase)); 
Cuestiones relacionadas