Come fare un LIKE senza distinzione tra maiuscole e minuscole in un database con distinzione tra maiuscole e minuscole?


11

Il mio fornitore richiede che il database del data warehouse sia sensibile al maiuscolo / minuscolo, ma è necessario eseguire query senza distinzione tra maiuscole e minuscole.

In un database con distinzione tra maiuscole e minuscole, come scriveresti per distinguere tra maiuscole e minuscole?

    Where Name like '%hospitalist%'

Risposte:


17

È possibile aggiungere un nuovo confronto alla query selezionata per trovare maiuscole o minuscole.

-- Case sensitive example
SELECT *
FROM TABLE 
WHERE Name collate SQL_Latin1_General_CP1_CS_AS like '%hospitalist%'

-- Case insensitive example
SELECT *
FROM TABLE 
WHERE Name collate SQL_Latin1_General_CP1_CI_AS like '%hospitalist%'

Basta essere consapevoli dei problemi di prestazioni che questo potrebbe presentare. Sarà necessario scansionare l'indice cluster per regolare / trovare i valori quando si esegue il confronto. Il modo in cui stai scrivendo il LIKEpezzo rende anche non interrogabile la query.

Ho preso il trucco della collazione dalle lezioni del seminario SELECT di Kendra Little . È possibile trovare ulteriori informazioni sulla raccolta tramite Ben Snaidero dai suggerimenti MS SQL.

MSDN su Fascicola.


@stom Esistono due metodi. A) Spostare i problemi di prestazioni sul tempo di elaborazione e non sul selecttempo. Puoi farlo creando una nuova colonna con un sottoinsieme dei dati trasformati e quindi indicizzandolo, in genere durante i periodi in cui eseguiresti ETL. Ciò avrebbe un costo di mantenimento e non è un ottimo metodo. B) È possibile rendere la ricerca della query discutibile o sargable. Modifica della query in modo che funzioni SELECT * FROM TABLE WHERE VALUE LIKE %hospitalisto SELECT * FROM TABLE WHERE VALUE LIKE hospitalist%funzionerebbe. A parte questo, stai guardando hardware o funzionalità per aumentare la velocità in caso di cattiva progettazione.
Shaulinator

14

Mentre è possibile utilizzare una funzione scalare, come SUPERIORE o INFERIORE e si può ri-fascicolare la colonna in modo che non è un caso più sensibili, questi approcci tutti richiedono la conversione dei dati essere fatto con i dati di base, che non permetterà mai che per un indice di ricerca. Stai anche guidando il tuo LIKE con un carattere jolly, quindi questo non è un grosso problema per te in questo scenario, ma se hai mai voluto cercare la parte sinistra di una stringa in modo efficiente E consentire l'ottimizzatore per cercare attraverso un indice, puoi specificare la tua stringa tra parentesi ([]) come segue:

SELECT *
FROM TABLE 
WHERE Name LIKE '[hH][oO][sS][pP][iI][tT][aA][lL][iI][sS][tT]%'

Questo esempio ( link dbfiddle qui ) fa un lavoro migliore nel mostrare cosa intendo:

CREATE TABLE #tmp_cohellation_fun
(
        ID  INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    ,   myValue VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CS_AS
)

-- Garbage values to represent data you don't want
INSERT INTO #tmp_cohellation_fun
SELECT  CAST(NEWID() AS VARCHAR(50))
FROM master.sys.configurations t1
    CROSS JOIN master.sys.configurations t2
    CROSS JOIN master.sys.configurations t3;

-- Sprinkle a little bit of good data
INSERT INTO #tmp_cohellation_fun
        (myValue)
VALUES  ('Apple')
    ,   ('apple')

-- Another healthy helping of garbage that we don't care about
INSERT INTO #tmp_cohellation_fun
SELECT  CAST(NEWID() AS VARCHAR(50))
FROM master.sys.configurations t1
    CROSS JOIN master.sys.configurations t2
    CROSS JOIN master.sys.configurations t3;

-- Some more good data
INSERT INTO #tmp_cohellation_fun
        (myValue)
VALUES
        ('aPple')
    ,   ('APPLE')
    ,   ('APple')


-- Final insert of garbage that we don't care about
INSERT INTO #tmp_cohellation_fun
SELECT  CAST(NEWID() AS VARCHAR(50))
FROM master.sys.configurations t1
    CROSS JOIN master.sys.configurations t2
    CROSS JOIN master.sys.configurations t3
;

-- Create a nonclustered rowstore index
CREATE INDEX ix_myValue ON #tmp_cohellation_fun (myValue)
;

SET STATISTICS XML ON
;

-- Seek, but incorrect results
SELECT  *
FROM    #tmp_cohellation_fun
WHERE   myValue LIKE 'apple%'
;

-- Scan, with correct results
SELECT  *
FROM    #tmp_cohellation_fun
WHERE   myValue COLLATE SQL_Latin1_General_CP1_CI_AS LIKE 'apple%'
;

-- Seek, with correct results
SELECT  *
FROM    #tmp_cohellation_fun
WHERE   myValue LIKE '[aA][pP][pP][lL][eE]%'
;

SET STATISTICS XML OFF
;

DROP TABLE IF EXISTS #tmp_cohellation_fun

Lo adoro. È al di là di me il motivo per cui SQL non potrebbe semplicemente eseguire il fallback con garbo come questo quando si dice fascicolazione da maiuscole e minuscole, quando si hanno due regole di confronto altrimenti identiche. Capisco perché non puoi andare dall'altra parte. Comunque questa è roba buona.
John Leidegren,

13

Sia questo che la COLLATErisposta avranno un impatto sulle prestazioni, perché rendono la query non SARGable , ma il modo più semplice per farlo (come suggerito da Edgar in un commento) è:

WHERE LOWER(Name) LIKE '%hospitalist%' 

o

WHERE UPPER(Name) LIKE '%HOSPITALIST%' 
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.