El servidor SQL ignora el caso en una expresión where

88

¿Cómo construyo una consulta SQL (MS SQL Server) donde la cláusula "where" no distingue entre mayúsculas y minúsculas?

SELECT * FROM myTable WHERE myField = 'sOmeVal'

Quiero que los resultados vuelvan ignorando el caso

Raúl Agrait
fuente

Respuestas:

136

En la configuración predeterminada de una base de datos de SQL Server, las comparaciones de cadenas no distinguen entre mayúsculas y minúsculas. Si su base de datos anula esta configuración (mediante el uso de una intercalación alternativa), deberá especificar qué tipo de intercalación utilizar en su consulta.

SELECT * FROM myTable WHERE myField = 'sOmeVal' COLLATE SQL_Latin1_General_CP1_CI_AS

Tenga en cuenta que la intercalación que proporcioné es solo un ejemplo (aunque es más que probable que funcione bien para usted). Puede encontrar un esquema más completo de las intercalaciones de SQL Server aquí .

Adam Robinson
fuente
Solo para confirmar, esto solo debe agregarse una vez, al final de la WHEREdeclaración, y afectará a todas las WHEREcláusulas, ¿correcto?
ashleedawg
¿Le gustaría saber si su respuesta tiene algún problema de rendimiento al convertir un valor de columna en UPPERo LOWERmayúsculas y luego usar LIKEpara buscar?
shaijut
1
@ashleedawg - buena pregunta ... parece ser una configuración por línea.
Leo Gurdian
29

Por lo general, las comparaciones de cadenas no distinguen entre mayúsculas y minúsculas. Si su base de datos está configurada para la intercalación que distingue entre mayúsculas y minúsculas, debe forzar el uso de una que no distinga entre mayúsculas y minúsculas:

SELECT balance FROM people WHERE email = '[email protected]'
  COLLATE SQL_Latin1_General_CP1_CI_AS 
Andrejs Cainikovs
fuente
@AskeB. and Andrejs: Técnicamente, esto no es un problema de configuración de la base de datos. Consulte mi respuesta para obtener una aclaración sobre las comparaciones de cadenas.
Solomon Rutzky
21

Encontré otra solución en otro lugar; es decir, usar

upper(@yourString)

pero todo el mundo aquí está diciendo que, en SQL Server, ¿no importa porque de todos modos está ignorando el caso? Estoy bastante seguro de que nuestra base de datos distingue entre mayúsculas y minúsculas.

Danny
fuente
6
Tiene razón en que una base de datos puede distinguirse entre mayúsculas y minúsculas, pero esto es bastante ineficiente, incluso si es necesario. COLLATE es la palabra clave a utilizar.
mjaggard
1
Gracias por mencionarlo, @mjaggard. Espero que usted, o cualquiera que parezca rechazar mi respuesta, elabore por el bien de cualquier persona como yo que busque y encuentre respuestas como la mía.
Danny
1
Voto esto ya que es una explicación perfectamente racional. Intercalar huele a demasiada sobrecarga y ¿qué pasa si su cadena tiene caracteres que la intercalación no comprende? Latin 1 es un esquema de codificación pésimo. Buena suerte para obtener resultados significativos si su cadena tiene un apóstrofo (como: O'Brien).
eggmatters
2
También votó a favor. Puedo pensar en muchos casos en los que esto sería útil. Además, a menudo hay más de una buena forma de hacer algo.
Inversus
1
Cambiar el caso de la cadena para fines de comparación es generalmente malo. En algunos idiomas, las conversiones de casos no son de ida y vuelta. es decir, INFERIOR (x)! = INFERIOR (SUPERIOR (x)).
Ceisc
14

Las 2 respuestas principales (de Adam Robinson y Andrejs Cainikovs ) son un poco correctas, ya que técnicamente funcionan, pero sus explicaciones son incorrectas y, por lo tanto, pueden ser engañosas en muchos casos. Por ejemplo, aunque la SQL_Latin1_General_CP1_CI_ASintercalación funcionará en muchos casos, no se debe suponer que sea la intercalación adecuada que no distingue entre mayúsculas y minúsculas. De hecho, dado que el OP está trabajando en una base de datos con una intercalación sensible a mayúsculas y minúsculas (o posiblemente binaria), sabemos que el OP no está utilizando la intercalación que es la predeterminada para tantas instalaciones (especialmente las instaladas en un sistema operativo) utilizando estadounidense Inglés como idioma): SQL_Latin1_General_CP1_CI_AS. Claro, el OP podría estar usandoSQL_Latin1_General_CP1_CS_AS , pero cuando se trabaja conVARCHARdatos, es importante no cambiar la página de códigos, ya que podría provocar la pérdida de datos, y eso está controlado por la configuración regional / cultura de la intercalación (es decir, Latin1_General vs French vs Hebrew, etc.). Consulte el punto 9 a continuación.

Las otras cuatro respuestas son incorrectas en diversos grados.

Aclararé todos los malentendidos aquí para que los lectores puedan tomar las decisiones más apropiadas / eficientes.

  1. No usar UPPER(). Eso es un trabajo extra completamente innecesario. Usa una COLLATEcláusula. Se debe realizar una comparación de cadenas en cualquier caso, pero el uso UPPER()también debe verificar, carácter por carácter, para ver si hay una asignación en mayúsculas y luego cambiarla. Y necesitas hacer esto en ambos lados. Agregar COLLATEsimplemente dirige el procesamiento para generar las claves de clasificación utilizando un conjunto de reglas diferente al que iba a utilizar de forma predeterminada. Usar COLLATEes definitivamente más eficiente (o "performante", si le gusta esa palabra :) que usar UPPER(), como se demuestra en este script de prueba (en PasteBin) .

    También está el problema señalado por @Ceisc en la respuesta de @ Danny:

    En algunos idiomas, las conversiones de casos no son de ida y vuelta. es decir, INFERIOR (x)! = INFERIOR (SUPERIOR (x)).

    La mayúscula turca "İ" es el ejemplo común.

  2. No, la intercalación no es una configuración para toda la base de datos, al menos no en este contexto. Existe una intercalación predeterminada en el nivel de la base de datos, y se usa como predeterminada para las columnas alteradas y recién creadas que no especifican la COLLATEcláusula (que es probablemente de donde proviene este error común), pero no afecta las consultas directamente a menos que usted esté comparar literales de cadena y variables con otras variables y literales de cadena, o está haciendo referencia a metadatos a nivel de base de datos.

  3. No, la intercalación no es por consulta.

  4. Las intercalaciones son por predicado (es decir, algo operando algo) o expresión, no por consulta. Y esto es cierto para toda la consulta, no solo para la WHEREcláusula. Esto cubre JOINs, GROUP BY, ORDER BY, PARTITION BY, etc.

  5. No, no convierta a VARBINARY(p convert(varbinary, myField) = convert(varbinary, 'sOmeVal'). Ej. ) Por las siguientes razones:

    1. esa es una comparación binaria, que no distingue entre mayúsculas y minúsculas (que es lo que pide esta pregunta)
    2. si desea una comparación binaria, utilice una intercalación binaria. Use uno que termine con _BIN2si está usando SQL Server 2008 o una versión más reciente; de ​​lo contrario, no tendrá más remedio que usar uno que termine con _BIN. Si los datos lo son NVARCHAR, no importa qué configuración regional use, ya que todos son iguales en ese caso, por Latin1_General_100_BIN2lo tanto, siempre funciona. Si los datos son VARCHAR, debe utilizar la misma configuración regional que los datos están actualmente en (por ejemplo Latin1_General, French, Japanese_XJIS, etc.), ya que la configuración regional determina la página de códigos que se utiliza, y el cambio de páginas de códigos puede alterar los datos (es decir, pérdida de datos).
    3. el uso de un tipo de datos de longitud variable sin especificar el tamaño dependerá del tamaño predeterminado, y hay dos valores predeterminados diferentes según el contexto en el que se esté utilizando el tipo de datos. Es 1 o 30 para tipos de cadena. Cuando se usa con CONVERT()él, usará el valor predeterminado de 30. El peligro es que si la cadena puede tener más de 30 bytes, se truncará silenciosamente y es probable que obtenga resultados incorrectos de este predicado.
    4. Incluso si desea una comparación que distinga entre mayúsculas y minúsculas, las intercalaciones binarias no distinguen entre mayúsculas y minúsculas (otro error muy común).
  6. No, LIKEno siempre distingue entre mayúsculas y minúsculas. Utiliza la intercalación de la columna a la que se hace referencia, o la intercalación de la base de datos si una variable se compara con un literal de cadena, o la intercalación especificada mediante la COLLATEcláusula opcional .

  7. LCASEno es una función de SQL Server. Parece ser Oracle o MySQL. ¿O posiblemente Visual Basic?

  8. Dado que el contexto de la pregunta es comparar una columna con un literal de cadena, ni la intercalación de la instancia (a menudo denominada "servidor") ni la intercalación de la base de datos tienen ningún impacto directo aquí. Las intercalaciones se almacenan por cada columna, y cada columna puede tener una intercalación diferente, y esas intercalaciones no necesitan ser las mismas que la intercalación predeterminada de la base de datos o la intercalación de la instancia. Claro, la intercalación de instancias es la predeterminada para lo que una base de datos recién creada usará como su intercalación predeterminada si la COLLATEcláusula no se especificó al crear la base de datos. Y del mismo modo, la intercalación predeterminada de la base de datos es lo que utilizará una columna modificada o recién creada si COLLATEno se especificó la cláusula.

  9. Debe utilizar la intercalación que no distingue entre mayúsculas y minúsculas, que por lo demás es la misma que la intercalación de la columna. Utilice la siguiente consulta para encontrar la intercalación de la columna (cambie el nombre de la tabla y el nombre del esquema):

    SELECT col.*
    FROM   sys.columns col
    WHERE  col.[object_id] = OBJECT_ID(N'dbo.TableName')
    AND    col.[collation_name] IS NOT NULL;
    

    Entonces solo cambia el _CSto be _CI. Entonces, Latin1_General_100_CS_ASse convertiría Latin1_General_100_CI_AS.

    Si la columna usa una intercalación binaria (terminada en _BINo _BIN2), busque una intercalación similar usando la siguiente consulta:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'{CurrentCollationMinus"_BIN"}[_]CI[_]%';
    

    Por ejemplo, asumiendo que la columna está usando Japanese_XJIS_100_BIN2, haga esto:

    SELECT *
    FROM   sys.fn_helpcollations() col
    WHERE  col.[name] LIKE N'Japanese_XJIS_100[_]CI[_]%';
    

Para obtener más información sobre intercalaciones, codificaciones, etc., visite: Información de intercalaciones

Salomón Rutzky
fuente
7

No, solo usarlo LIKEno funcionará. LIKEbusca valores que coincidan exactamente con su patrón dado. En este caso LIKE, solo encontraría el texto 'sOmeVal' y no 'someval'.

Una solución práctica es usar la LCASE()función. LCASE('sOmeVal')obtiene la cadena en minúsculas de su texto: 'someval'. Si usa esta función para ambos lados de su comparación, funciona:

SELECT * FROM myTable WHERE LCASE(myField) LIKE LCASE('sOmeVal')

La declaración compara dos cadenas en minúsculas, de modo que su 'sOmeVal' coincidirá con cualquier otra notación de 'someval' (por ejemplo, 'Someval', 'sOMEVAl', etc.).

David Hermanns
fuente
7
En el 99,9% de las instalaciones de SQL Server que se clasifican en _CI, LIKE no distingue entre mayúsculas y minúsculas.
RichardTheKiwi
1
Hoy en día la función se llama LOWER
David Brossard
@DavidBrossard y David Hermanns, no creo que haya estado nunca LCASE()en SQL Server (al menos no que yo pueda ver). Creo que esta respuesta es para un RDBMS completamente diferente. Consulte mi respuesta para obtener una aclaración sobre las comparaciones de cadenas.
Solomon Rutzky
4

Puede forzar la distinción entre mayúsculas y minúsculas, lanzando a un varbinary como ese:

SELECT * FROM myTable 
WHERE convert(varbinary, myField) = convert(varbinary, 'sOmeVal')

fuente
3
Si bien esto es funcional, no es un enfoque recomendable. Las intercalaciones están ahí para gestionar la clasificación y las comparaciones de cadenas.
Adam Robinson
@AdamRobinson, ¿no se trata de "comparaciones de cadenas"?
Fandango68
@ Fandango68 Sí, lo es, y Adam dice que las intercalaciones son mejores cuando se hacen comparaciones de cadenas.
JLRishe
@ Fandango68 Esta respuesta es incorrecta en varios niveles. Por favor, vea mi respuesta para más detalles, especialmente el punto 5.
Solomon Rutzky
@AdamRobinson Consulte mi respuesta para obtener una aclaración sobre las comparaciones de cadenas.
Solomon Rutzky
2

¿En qué base de datos estás? Con MS SQL Server, es una configuración para toda la base de datos, o puede anularla por consulta con la palabra clave COLLATE.

Chase Seibert
fuente
Hola. Para SQL Server, en términos de lo que trata esta pregunta, no es una configuración para toda la base de datos ni por consulta. Consulte mi respuesta para obtener más detalles.
Solomon Rutzky