Wie mache ich ein LIKE ohne Berücksichtigung der Groß- und Kleinschreibung in einer Datenbank mit Groß- und Kleinschreibung?

11

Mein Lieferant verlangt, dass in der Data Warehouse-Datenbank zwischen Groß- und Kleinschreibung unterschieden wird, ich muss jedoch zwischen Groß- und Kleinschreibung unterscheiden.

Wie würden Sie in einer Datenbank mit Groß- und Kleinschreibung die Groß- und Kleinschreibung beachten?

    Where Name like '%hospitalist%'
James
quelle

Antworten:

17

Sie können Ihrer ausgewählten Abfrage eine neue Sortierung hinzufügen, um zwischen Groß- und Kleinschreibung zu unterscheiden.

-- 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%'

Beachten Sie nur die möglichen Leistungsprobleme. Sie müssen den Clustered-Index scannen, um die Werte anzupassen / zu finden, wenn Sie die Sortierung durchführen. Die Art und Weise, wie Sie das LIKEStück schreiben, macht die Abfrage auch nicht sargable.

Ich habe den Kollationstrick aus Kendra Littles SELECT-Seminarklassen übernommen. Weitere Informationen zur Sortierung finden Sie bei Ben Snaidero in MS SQL Tips.

MSDN beim Sortieren.

Shaulinator
quelle
@stom Es gibt zwei Methoden. Entweder a) Verschieben Sie die Leistungsprobleme in die Verarbeitungszeit und nicht in die selectZeit. Sie können dies tun, indem Sie eine neue Spalte mit einer Teilmenge der transformierten Daten erstellen und diese dann indizieren, normalerweise zu Zeiten, in denen Sie ETL ausführen würden. Dies hätte Unterhaltskosten und ist keine gute Methode. B) Sie können die Abfragesuche streitig oder sargbar machen. Ändern der Abfrage so, dass sie funktioniert SELECT * FROM TABLE WHERE VALUE LIKE %hospitalistoder SELECT * FROM TABLE WHERE VALUE LIKE hospitalist%funktionieren würde. Abgesehen davon suchen Sie nach Hardware oder Funktionen, um die Geschwindigkeit bei schlechtem Design zu erhöhen.
Shaulinator
13

Während Sie können eine skalare Funktion wie verwenden UPPER oder LOWER und Sie können die Spalte so neu zusammenzustellen , dass es nicht mehr Groß- und Kleinschreibung ist, nähert sich diese alle Datenkonvertierung erforderlich gegen den Basisdaten erfolgen, die niemals versuchen , für einen Index ermöglicht. Sie führen Ihr LIKE auch mit einem Platzhalter an, sodass dies in diesem Szenario ohnehin nicht so wichtig für Sie ist, aber wenn Sie jemals effizient nach dem linken Teil einer Zeichenfolge suchen und den Optimierer berücksichtigen wollten Um einen Index zu durchsuchen, können Sie Ihre Zeichenfolge in Klammern ([]) wie folgt angeben:

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

Dieses Beispiel ( Link dbfiddle hier ) zeigt besser, was ich meine:

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
John Eisbrener
quelle
Liebe es. Es ist mir ein Rätsel, warum SQL nicht einfach so elegant zurückgreifen kann, wenn Sie sagen, dass die Sortierung von Groß- und Kleinschreibung zu Groß- und Kleinschreibung nicht unterscheidet, wenn Sie zwei ansonsten identische Kollatierungen haben. Ich verstehe, warum du nicht in die andere Richtung gehen kannst. Jedenfalls ist das gutes Zeug.
John Leidegren
12

Sowohl dies als auch die COLLATEAntwort wirken sich auf die Leistung aus, da die Abfrage nicht SARG-fähig ist. Der einfachste Weg, dies zu tun (wie Edgar in einem Kommentar vorgeschlagen hat), ist jedoch:

WHERE LOWER(Name) LIKE '%hospitalist%' 

oder

WHERE UPPER(Name) LIKE '%HOSPITALIST%' 
BradC
quelle