Bagaimana cara SEPERTI case-insensitive dalam database case-sensitive?

11

Vendor saya mengharuskan database data warehouse menjadi case-sensitive, tetapi saya perlu melakukan query case-insensitive terhadapnya.

Dalam database case-sensitive, bagaimana Anda menulis ini menjadi case-sensitive?

    Where Name like '%hospitalist%'
James
sumber

Jawaban:

17

Anda dapat menambahkan susunan baru ke kueri pemilihan Anda untuk menemukan case sensitif atau tidak sensitif.

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

Sadarilah masalah kinerja yang dapat terjadi. Anda perlu memindai indeks berkerumun untuk menyesuaikan / menemukan nilai saat Anda melakukan pemeriksaan. Cara Anda menulis LIKEkarya juga membuat kueri tidak dapat ditagih.

Saya mengambil trik susun dari kelas SELECT Seminar Kendra Little . Anda dapat menemukan informasi pemeriksaan tambahan dari Ben Snaidero dari MS SQL Tips.

MSDN di Susun.

Shaulinator
sumber
@stom Ada dua metode. Baik a) Pindahkan masalah kinerja ke waktu pemrosesan dan bukan selectwaktu. Anda dapat melakukan ini dengan membuat kolom baru dengan subset dari data yang ditransformasi dan kemudian mengindeksnya, biasanya pada saat-saat ketika Anda akan menjalankan ETL. Ini akan memiliki biaya pemeliharaan dan bukan metode yang bagus. B) Anda dapat membuat pencarian kueri diperdebatkan, atau dapat dikalahkan. Mengubah kueri menjadi SELECT * FROM TABLE WHERE VALUE LIKE %hospitalistatau SELECT * FROM TABLE WHERE VALUE LIKE hospitalist%akan berfungsi. Terlepas dari itu, Anda mencari perangkat keras atau fitur untuk meningkatkan kecepatan pada desain yang buruk.
Shaulinator
14

Meskipun Anda dapat menggunakan fungsi skalar seperti UPPER atau RENDAH dan Anda dapat menyusun ulang kolom sehingga tidak lagi peka huruf besar-kecil, semua pendekatan ini mengharuskan konversi data dilakukan terhadap data dasar yang tidak akan pernah memungkinkan untuk pencarian indeks. Anda juga memimpin LIKE Anda dengan wildcard, jadi ini bukan masalah bagi Anda dalam skenario ini, tetapi jika Anda pernah ingin mencari bagian kiri dari string dengan cara yang efisien DAN memungkinkan pengoptimal untuk mencari melalui indeks, Anda dapat menentukan string Anda dengan tanda kurung ([]) sebagai berikut:

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

Contoh ini ( tautan dbfiddle di sini ) melakukan pekerjaan yang lebih baik untuk menunjukkan apa yang saya maksud:

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
sumber
Suka. Ini di luar saya mengapa SQL tidak bisa hanya mundur dengan anggun seperti ini ketika Anda mengatakan susun dari peka terhadap kasus tidak peka, ketika Anda memiliki dua kumpulan yang identik. Saya mengerti mengapa Anda tidak bisa memilih jalan lain. Bagaimanapun ini adalah hal yang baik.
John Leidegren
13

Baik ini maupun COLLATEjawabannya akan memengaruhi kinerja, karena mereka membuat kueri tidak-SARGable , tetapi cara termudah untuk melakukannya (seperti yang disarankan Edgar dalam komentar) adalah:

WHERE LOWER(Name) LIKE '%hospitalist%' 

atau

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