Il server SQL ignora il caso in un'espressione where


88

Come faccio a costruire una query SQL (MS SQL Server) in cui la clausola "where" non fa distinzione tra maiuscole e minuscole?

SELECT * FROM myTable WHERE myField = 'sOmeVal'

Voglio che i risultati tornino ignorando il caso

Risposte:


136

Nella configurazione predefinita di un database di SQL Server, i confronti tra stringhe non fanno distinzione tra maiuscole e minuscole. Se il database sostituisce questa impostazione (tramite l'uso di regole di confronto alternative), sarà necessario specificare il tipo di regole di confronto da utilizzare nella query.

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

Nota che le regole di confronto che ho fornito sono solo un esempio (anche se molto probabilmente funzionerà bene per te). Una descrizione più completa delle regole di confronto di SQL Server è disponibile qui .


Solo per confermare, questo deve essere aggiunto solo una volta, alla fine della WHEREdichiarazione, e influenzerà tutte le WHEREclausole, giusto?
ashleedawg

Vuoi sapere se la tua risposta ha problemi di prestazioni convertendo un valore di colonna in UPPERo LOWERcaso quindi utilizzando il LIKEper cercare?
shaijut

1
@ashleedawg - bella domanda .. sembra essere un'impostazione per riga.
Leo Gurdian

29

Di solito, i confronti tra stringhe non fanno distinzione tra maiuscole e minuscole. Se il database è configurato per le regole di confronto con distinzione tra maiuscole e minuscole, è necessario forzarne l'uso senza distinzione tra maiuscole e minuscole:

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

@AskeB. e Andrejs: Questo non è tecnicamente un problema di configurazione del database. Si prega di consultare la mia risposta per chiarimenti sui confronti di stringhe.
Solomon Rutzky,

21

Ho trovato un'altra soluzione altrove; cioè da usare

upper(@yourString)

ma tutti qui dicono che, in SQL Server, non importa perché ignora comunque il caso? Sono abbastanza sicuro che il nostro database fa distinzione tra maiuscole e minuscole.


6
Hai ragione sul fatto che un database può essere sensibile al maiuscolo / minuscolo, ma questo è piuttosto inefficiente, anche se è necessario. COLLATE è la parola chiave da utilizzare.
mjaggard

1
Grazie per averne parlato, @mjaggard. Spero che tu, o chiunque sembri sottovalutare la mia risposta, elabori per il bene di chiunque come me cerchi e trovi risposte come la mia.
Danny

1
Votato questo in quanto è una spiegazione perfettamente razionale. Fascicola un po 'di overhead e cosa succede se la tua stringa contiene caratteri che la collation non comprende? Il latino 1 è uno schema di codifica scadente. Buona fortuna per ottenere risultati significativi se la tua stringa contiene un apostrofo (come: O'Brien).
pasta d'uovo

2
Anche votato. Mi vengono in mente molti casi in cui ciò sarebbe utile. Inoltre, spesso c'è più di un buon modo per fare qualcosa.
Inversus

1
Cambiare il caso della stringa per scopi di confronto è generalmente sbagliato. In alcune lingue le conversioni dei casi non vengono eseguite in andata e ritorno. cioè LOWER (x)! = LOWER (UPPER (x)).
Ceisc

14

Le prime 2 risposte (da Adam Robinson e Andrejs Cainikovs ) sono un po 'corrette, in quanto tecnicamente funzionano, ma le loro spiegazioni sono sbagliate e quindi potrebbero essere fuorvianti in molti casi. Ad esempio, sebbene le SQL_Latin1_General_CP1_CI_ASregole di confronto funzionino in molti casi, non si dovrebbe presumere che siano le regole di confronto appropriate senza distinzione tra maiuscole e minuscole. Infatti, dato che l'OP sta lavorando in un database con un confronto case-sensitive (o possibilmente binario), sappiamo che l'OP non sta usando il confronto che è l'impostazione predefinita per così tante installazioni (specialmente quelle installate su un sistema operativo usando gli Stati Uniti l'inglese come lingua): SQL_Latin1_General_CP1_CI_AS. Certo, l'OP potrebbe essere utilizzato SQL_Latin1_General_CP1_CS_AS, ma quando si lavora conVARCHARdata, è importante non modificare la code page in quanto potrebbe portare alla perdita di dati, e ciò è controllato dalle impostazioni locali / cultura delle regole di confronto (ad esempio Latin1_General vs French vs Hebrew ecc). Si prega di vedere il punto 9 di seguito.

Le altre quattro risposte sono sbagliate a vari livelli.

Chiarirò qui tutti i malintesi in modo che i lettori possano, si spera, fare le scelte più appropriate / efficienti.

  1. Non utilizzare UPPER(). Questo è un lavoro extra completamente inutile. Usa una COLLATEclausola. In entrambi i casi è necessario eseguire un confronto tra stringhe, ma using UPPER()deve anche controllare, carattere per carattere, se è presente una mappatura maiuscola, quindi modificarla. E devi farlo su entrambi i lati. L'aggiunta COLLATEindica semplicemente all'elaborazione di generare le chiavi di ordinamento utilizzando un insieme di regole diverso da quello predefinito. L'uso COLLATEè decisamente più efficiente (o "performante", se ti piace quella parola :) che usare UPPER(), come dimostrato in questo script di test (su PasteBin) .

    C'è anche il problema notato da @Ceisc sulla risposta di @ Danny:

    In alcune lingue, le conversioni dei casi non vengono eseguite in andata e ritorno. cioè LOWER (x)! = LOWER (UPPER (x)).

    La lettera maiuscola turca "İ" è l'esempio comune.

  2. No, le regole di confronto non sono un'impostazione a livello di database, almeno non in questo contesto. Esistono regole di confronto predefinite a livello di database e vengono utilizzate come impostazioni predefinite per le colonne modificate e di nuova creazione che non specificano la COLLATEclausola (che è probabile da cui provenga questo malinteso comune), ma non influisce direttamente sulle query a meno che tu non lo sia confrontando i valori letterali e le variabili stringa con altri valori letterali e variabili stringa oppure si fa riferimento a metadati a livello di database.

  3. No, le regole di confronto non sono per query.

  4. Le regole di confronto sono per predicato (cioè qualcosa di operando qualcosa) o espressione, non per query. E questo è vero per l'intera query, non solo per la WHEREclausola. Questo copre JOINs, GROUP BY, ORDER BY, PARTITION BY, ecc.

  5. No, non convertire in VARBINARY(ad es. convert(varbinary, myField) = convert(varbinary, 'sOmeVal')) Per i seguenti motivi:

    1. questo è un confronto binario, che non fa distinzione tra maiuscole e minuscole (che è ciò che questa domanda chiede)
    2. se vuoi un confronto binario, usa un confronto binario. Usane uno che finisca con _BIN2se stai usando SQL Server 2008 o più recente, altrimenti non hai altra scelta che usarne uno che finisca con _BIN. Se i dati sono NVARCHAR, non importa quale locale usi poiché sono tutti uguali in quel caso, quindi Latin1_General_100_BIN2funziona sempre. Se i dati sono VARCHAR, è necessario utilizzare la stessa impostazione internazionale che i dati sono attualmente in (ad esempio Latin1_General, French, Japanese_XJIS, ecc), perché l'impostazione internazionale determina la pagina di codice che viene utilizzato, e la modifica di pagine di codice in grado di alterare i dati (ad esempio perdita di dati).
    3. l'utilizzo di un tipo di dati a lunghezza variabile senza specificare la dimensione dipenderà dalla dimensione predefinita e sono disponibili due impostazioni predefinite diverse a seconda del contesto in cui viene utilizzato il tipo di dati. È 1 o 30 per i tipi di stringa. Quando viene utilizzato con CONVERT()esso, utilizzerà il valore predefinito 30. Il pericolo è che, se la stringa può superare i 30 byte, verrà troncata silenziosamente e probabilmente otterrai risultati errati da questo predicato.
    4. Anche se si desidera un confronto con distinzione tra maiuscole e minuscole, le regole di confronto binarie non sono sensibili al maiuscolo / minuscolo (un altro malinteso molto comune).
  6. No, LIKEnon fa sempre distinzione tra maiuscole e minuscole. Utilizza le regole di confronto della colonna a cui si fa riferimento o le regole di confronto del database se una variabile viene confrontata con un valore letterale stringa o le regole di confronto specificate tramite la COLLATEclausola facoltativa .

  7. LCASEnon è una funzione di SQL Server. Sembra essere Oracle o MySQL. O forse Visual Basic?

  8. Poiché il contesto della domanda sta confrontando una colonna con una stringa letterale, né il confronto dell'istanza (spesso denominato "server") né il confronto del database hanno alcun impatto diretto qui. Le regole di confronto vengono archiviate per ogni colonna e ogni colonna può avere regole di confronto diverse e non è necessario che tali regole di confronto siano le stesse delle regole di confronto predefinite del database o dell'istanza. Certo, le regole di confronto dell'istanza sono l'impostazione predefinita per ciò che un database appena creato utilizzerà come regole di confronto predefinite se la COLLATEclausola non è stata specificata durante la creazione del database. Allo stesso modo, le regole di confronto predefinite del database sono ciò che una colonna modificata o appena creata utilizzerà se la COLLATEclausola non è stata specificata.

  9. È necessario utilizzare le regole di confronto senza distinzione tra maiuscole e minuscole, altrimenti le stesse delle regole di confronto della colonna. Utilizzare la seguente query per trovare le regole di confronto della colonna (modificare il nome della tabella e il nome dello schema):

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

    Quindi cambia semplicemente _CSessere _CI. Quindi, Latin1_General_100_CS_ASsarebbe diventato Latin1_General_100_CI_AS.

    Se la colonna utilizza un confronto binario (che termina con _BINo _BIN2), trova un confronto simile utilizzando la query seguente:

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

    Ad esempio, supponendo che la colonna stia usando Japanese_XJIS_100_BIN2, fai questo:

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

Per maggiori informazioni su regole di confronto, codifiche, ecc., Visitare: Informazioni sulle collazioni


7

No, solo l'utilizzo LIKEnon funzionerà. LIKEcerca i valori che corrispondono esattamente al modello fornito. In questo caso LIKEtroverà solo il testo "sOmeVal" e non "someval".

Una soluzione pratica è usare la LCASE()funzione. LCASE('sOmeVal')ottiene la stringa minuscola del testo: 'someval'. Se utilizzi questa funzione per entrambi i lati del confronto, funziona:

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

L'istruzione confronta due stringhe minuscole, in modo che 'sOmeVal' corrisponda a ogni altra notazione di 'someval' (ad esempio 'Someval', 'sOMEVAl' ecc.).


7
Nel 99,9% delle installazioni di SQL Server che vengono confrontate con _CI, LIKE è Case Insensitive.
RichardTheKiwi

1
Al giorno d'oggi la funzione si chiama LOWER
David Brossard

@DavidBrossard e David Hermanns, non credo sia mai stato LCASE()in SQL Server (almeno non che io possa vedere). Penso che questa risposta sia per un RDBMS completamente diverso. Si prega di consultare la mia risposta per chiarimenti sui confronti di stringhe.
Solomon Rutzky

4

Puoi forzare la distinzione tra maiuscole e minuscole, eseguendo il casting su un varbinary in questo modo:

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

3
Sebbene sia funzionale, non è un approccio consigliabile. Le regole di confronto sono disponibili per la gestione dell'ordinamento e dei confronti di stringhe.
Adam Robinson

@AdamRobinson non si tratta di "confronti di stringhe" però?
Fandango68

@ Fandango68 Sì, e Adam dice che le regole di confronto sono migliori quando si eseguono confronti tra stringhe.
JLRishe

@ Fandango68 Questa risposta è sbagliata su diversi livelli. Si prega di consultare la mia risposta per i dettagli, in particolare il punto 5.
Solomon Rutzky

@AdamRobinson Si prega di vedere la mia risposta per chiarimenti sui confronti di stringhe.
Solomon Rutzky

2

Su quale database ti trovi? Con MS SQL Server, è un'impostazione a livello di database oppure puoi sovrascriverla per query con la parola chiave COLLATE.


Ciao. Per SQL Server, in termini di cosa tratta questa domanda, non è né un'impostazione a livello di database né per query. Si prega di consultare la mia risposta per i dettagli.
Solomon Rutzky
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.