O servidor SQL ignora maiúsculas e minúsculas em uma expressão where


91

Como faço para construir uma consulta SQL (MS SQL Server) em que a cláusula "where" não diferencia maiúsculas de minúsculas?

SELECT * FROM myTable WHERE myField = 'sOmeVal'

Eu quero que os resultados voltem ignorando o caso

Respostas:


137

Na configuração padrão de um banco de dados SQL Server, comparações de string são case-insensitive. Se o seu banco de dados substituir essa configuração (por meio do uso de um agrupamento alternativo), você precisará especificar que tipo de agrupamento usar em sua consulta.

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

Observe que o agrupamento que forneci é apenas um exemplo (embora seja mais do que provável que funcione bem para você). Um esboço mais completo dos agrupamentos do SQL Server pode ser encontrado aqui .


Só para confirmar, só precisa ser adicionado uma vez, no final do WHEREenunciado, e afetará todas as WHEREcláusulas, correto?
— ashleedawg

Gostaria de saber se sua resposta apresenta algum problema de desempenho ao converter um valor de coluna para UPPERou LOWERmaiúsculas e minúsculas e usar o LIKEpara pesquisar?
— Shaiju T

1
@ashleedawg - boa pergunta .. parece ser uma configuração por linha.
— Leo Gurdian

30

Normalmente, as comparações de strings não diferenciam maiúsculas de minúsculas. Se seu banco de dados estiver configurado para agrupamento que diferencia maiúsculas de minúsculas, você precisa forçar o uso de um que não diferencia maiúsculas de minúsculas:

SELECT balance FROM people WHERE email = 'billg@microsoft.com'
  COLLATE SQL_Latin1_General_CP1_CI_AS 

@AskeB. e Andrejs: Este não é tecnicamente um problema de configuração do banco de dados. Por favor, veja minha resposta para esclarecimentos sobre comparações de strings.
— Solomon Rutzky

21

Encontrei outra solução em outro lugar; isto é, usar

upper(@yourString)

mas todo mundo aqui está dizendo que, no SQL Server, não importa porque está ignorando maiúsculas de qualquer maneira? Tenho certeza que nosso banco de dados diferencia maiúsculas de minúsculas.


7
Você está certo de que um banco de dados pode ser sensível a maiúsculas e minúsculas, mas isso é bastante ineficiente, mesmo se necessário. COLLATE é a palavra-chave a ser usada.
— mjaggard

1
Obrigado por trazer isso à tona, @mjaggard. Espero que você, ou qualquer pessoa que pareça rejeitar minha resposta, elabore para o bem de alguém como eu, que procura e encontra respostas como a minha.
— Danny

1
Votei positivamente nisso, pois é uma explicação perfeitamente racional. Agrupe cheiros de muito overhead e se sua string contiver caracteres que o agrupamento não entende? Latim 1 é um péssimo esquema de codificação. Boa sorte para obter resultados significativos se sua string contiver um apóstrofo (como: O'Brien).
— Eggmatters de

2
Também votado positivamente. Posso pensar em muitos casos em que isso seria útil. Além disso, geralmente há mais de uma boa maneira de fazer algo.
— Inversus

1
Alterar o caso da string para fins de comparação geralmente é ruim. Em alguns idiomas, as conversões de caso não são de ida e volta. isto é, LOWER (x)! = LOWER (UPPER (x)).
— Ceisc de

17

As 2 principais respostas (de Adam Robinson e Andrejs Cainikovs ) são meio, meio corretas, no sentido de que funcionam tecnicamente, mas suas explicações estão erradas e, portanto, podem ser enganosas em muitos casos. Por exemplo, embora o SQL_Latin1_General_CP1_CI_ASagrupamento funcione em muitos casos, ele não deve ser considerado o agrupamento adequado, sem distinção entre maiúsculas e minúsculas. Na verdade, dado que o OP está trabalhando em um banco de dados com um agrupamento que diferencia maiúsculas de minúsculas (ou possivelmente binário), sabemos que o OP não está usando o agrupamento que é o padrão para muitas instalações (especialmente qualquer instalado em um sistema operacional usando US Inglês como língua): SQL_Latin1_General_CP1_CI_AS. Claro, o OP pode estar usando SQL_Latin1_General_CP1_CS_AS, mas ao trabalhar comVARCHARdados, é importante não alterar a página de código, pois isso pode levar à perda de dados e isso é controlado pela localidade / cultura do agrupamento (ou seja, Latin1_General vs francês vs hebraico etc.). Por favor, veja o ponto # 9 abaixo.

As outras quatro respostas estão erradas em vários graus.

Esclarecerei todos os mal-entendidos aqui para que os leitores possam fazer as escolhas mais apropriadas / eficientes.

  1. Não use UPPER(). Isso é um trabalho extra completamente desnecessário. Use uma COLLATEcláusula. Uma comparação de string precisa ser feita em ambos os casos, mas o uso UPPER()também tem que verificar, caractere por caractere, para ver se há um mapeamento em maiúsculas e, em seguida, alterá-lo. E você precisa fazer isso dos dois lados. Adicionar COLLATEsimplesmente direciona o processamento para gerar as chaves de classificação usando um conjunto de regras diferente daquele usado por padrão. Usar COLLATEé definitivamente mais eficiente (ou "performante", se você gosta dessa palavra :) do que usar UPPER(), como comprovado neste script de teste (em PasteBin) .

    Há também o problema observado por @Ceisc na resposta de @ Danny:

    Em alguns idiomas, as conversões de caso não são de ida e volta. ou seja, LOWER (x)! = LOWER (UPPER (x)).

    A maiúscula turca "İ" é o exemplo comum.

  2. Não, o agrupamento não é uma configuração de todo o banco de dados, pelo menos não neste contexto. Há um agrupamento padrão no nível do banco de dados e é usado como padrão para colunas alteradas e criadas recentemente que não especificam a COLLATEcláusula (que é provavelmente de onde vem esse equívoco comum), mas não afeta as consultas diretamente, a menos que você comparando literais e variáveis ​​de string com outros literais e variáveis ​​de string, ou você está fazendo referência a metadados no nível do banco de dados.

  3. Não, o agrupamento não é por consulta.

  4. Os agrupamentos são por predicado (ou seja, algo operando algo) ou expressão, não por consulta. E isso é verdade para toda a consulta, não apenas para a WHEREcláusula. Isso cobre JOINs, GROUP BY, ORDER BY, PARTITION BY, etc.

  5. Não, não converta para VARBINARY(por exemplo convert(varbinary, myField) = convert(varbinary, 'sOmeVal')) pelos seguintes motivos:

    1. essa é uma comparação binária, que não faz distinção entre maiúsculas e minúsculas (que é o que esta pergunta está pedindo)
    2. se você quiser uma comparação binária, use um agrupamento binário. Use um que termine com _BIN2se estiver usando o SQL Server 2008 ou mais recente; caso contrário, você não terá escolha a não ser usar um que termine com _BIN. Se os dados forem NVARCHAR, não importa qual local você usar, pois todos são iguais nesse caso, portanto, Latin1_General_100_BIN2sempre funciona. Se os dados forem VARCHAR, você deve usar o mesmo local que os dados estão atualmente em (por exemplo Latin1_General, French,Japanese_XJIS , etc), porque o local determina a página de código que é usado, e mudar as páginas de código pode alterar os dados (perda de dados IE).
    3. usar um tipo de dados de comprimento variável sem especificar o tamanho dependerá do tamanho padrão, e há dois padrões diferentes dependendo do contexto em que o tipo de dados está sendo usado. É 1 ou 30 para tipos de string. Quando usado com CONVERT()ele, usará o valor padrão 30. O perigo é que, se a string pode ter mais de 30 bytes, ela ficará silenciosamente truncada e você provavelmente obterá resultados incorretos com esse predicado.
    4. Mesmo se você quiser uma comparação com distinção entre maiúsculas e minúsculas, os agrupamentos binários não diferenciam maiúsculas de minúsculas (outro equívoco muito comum).
  6. Não, LIKEnem sempre diferencia maiúsculas de minúsculas. Ele usa o agrupamento da coluna que está sendo referenciada, ou o agrupamento do banco de dados se uma variável for comparada a um literal de string ou o agrupamento especificado por meio da COLLATEcláusula opcional .

  7. LCASEnão é uma função do SQL Server. Parece ser Oracle ou MySQL. Ou possivelmente Visual Basic?

  8. Uma vez que o contexto da questão está comparando uma coluna a um literal de string, nem o agrupamento da instância (muitas vezes referido como "servidor") nem o agrupamento do banco de dados têm qualquer impacto direto aqui. Os agrupamentos são armazenados para cada coluna e cada coluna pode ter um agrupamento diferente, e esses agrupamentos não precisam ser iguais ao agrupamento padrão do banco de dados ou ao agrupamento da instância. Claro, o agrupamento de instância é o padrão para o que um banco de dados recém-criado usará como seu agrupamento padrão se a COLLATEcláusula não foi especificada ao criar o banco de dados. E da mesma forma, o agrupamento padrão do banco de dados é o que uma coluna alterada ou recém-criada usará se a COLLATEcláusula não for especificada.

  9. Você deve usar o agrupamento que não diferencia maiúsculas de minúsculas que, de outra forma, é o mesmo que o agrupamento da coluna. Use a seguinte consulta para encontrar o agrupamento da coluna (altere o nome da tabela e o nome do esquema):

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

    Em seguida, basta alterar o _CSpara ser _CI. Então, Latin1_General_100_CS_ASse tornaria Latin1_General_100_CI_AS.

    Se a coluna estiver usando um agrupamento binário (terminando em _BINou _BIN2), encontre um agrupamento semelhante usando a seguinte consulta:

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

    Por exemplo, supondo que a coluna esteja usando Japanese_XJIS_100_BIN2, faça o seguinte:

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

Para mais informações sobre agrupamentos, codificações, etc, visite: Collations Informações


7

Não, apenas o uso LIKEnão funcionará. LIKEprocura valores que correspondam exatamente ao seu padrão fornecido. Neste caso LIKE, encontraria apenas o texto 'sOmeVal' e não 'someval'.

Uma solução prática é usar a LCASE()função. LCASE('sOmeVal')obtém a string minúscula do seu texto: 'someval'. Se você usar esta função para ambos os lados da comparação, ela funcionará:

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

A instrução compara duas strings em minúsculas, de modo que seu 'sOmeVal' corresponderá a todas as outras notações de 'someval' (por exemplo, 'Someval', 'sOMEVAl' etc.).


7
Em 99,9% das instalações do SQL Server que são agrupadas _CI, LIKE não faz distinção entre maiúsculas e minúsculas.
— RichardTheKiwi

1
Hoje em dia a função chama-se LOWER
— David Brossard

@DavidBrossard e David Hermanns, acho que nunca foi LCASE()no SQL Server (pelo menos não que eu consiga ver). Acho que essa resposta é para um RDBMS totalmente diferente. Por favor, veja minha resposta para esclarecimentos sobre comparações de strings.
— Solomon Rutzky

4

Você pode forçar a distinção entre maiúsculas e minúsculas, convertendo para um varbinary como este:

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

3
Embora seja funcional, não é uma abordagem aconselhável. Os agrupamentos existem para gerenciar a classificação e as comparações de strings.
— Adam Robinson

@AdamRobinson não é sobre "comparações de strings"?
— Fandango68

@ Fandango68 Sim, é, e Adam está dizendo que agrupamentos são melhores ao fazer comparações de strings.
— JLRishe

@ Fandango68 Essa resposta está errada em vários níveis. Por favor, veja minha resposta para detalhes, especialmente ponto 5.
— Solomon Rutzky

@AdamRobinson Por favor, veja minha resposta para esclarecimentos sobre comparações de strings.
— Solomon Rutzky

2

Em qual banco de dados você está? Com o MS SQL Server, é uma configuração para todo o banco de dados, ou você pode substituí-la por consulta com a palavra-chave COLLATE.


Olá. Para o SQL Server, em termos do que trata esta questão, não é uma configuração de todo o banco de dados nem por consulta. Por favor, veja minha resposta para detalhes.
— Solomon Rutzky
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.