web-dev-qa-db-ja.com

大文字と小文字を区別するデータベースで大文字と小文字を区別しないLIKEを行う方法

私のベンダーでは、データウェアハウスデータベースで大文字と小文字を区別する必要がありますが、それに対して大文字と小文字を区別しないクエリを実行する必要があります。

大文字と小文字を区別するデータベースで、大文字と小文字を区別しないようにこれをどのように記述しますか?

    Where Name like '%hospitalist%'
9
James

選択クエリに新しい照合を追加して、大文字と小文字を区別するか区別しないかを見つけることができます。

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

これが示す可能性のあるパフォーマンスの問題に注意してください。照合を実行するときは、クラスター化インデックスをスキャンして値を調整/検索する必要があります。 LIKEピースの記述方法によっても、クエリは検索不可能になります。

Kendra Little's SELECTセミナークラスから照合トリックを取得しました。 MS SQLのヒントから Ben Snaideroから追加の照合情報を見つけることができます

コレート上のMSDN

15
Shaulinator

あなたがすることができますが[〜#〜] upper [〜#〜] または などのスカラー関数を使用します[〜#〜] lower [〜#〜] そして、canカラムを再照合して、大文字と小文字を区別しないようにします。これらのアプローチすべては、インデックスシークを許可しない基本データに対してデータ変換を行う必要があります。また、ワイルドカードを使用してLIKEをリードしているため、これはこのシナリオではそれほど心配する必要はありませんが、文字列の左側を効率的な方法で検索したい場合[〜#〜]および[〜#〜]を使用すると、オプティマイザがインデックスをシークできます。次のように、角括弧([])を使用して文字列を指定できます。

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

この例( dbfiddle link here )は、私が何を意味しているのかを示すのにより良い仕事をしています:

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
13
John Eisbrener

これとCOLLATEの両方の回答は、パフォーマンスに影響を及ぼします。これらは クエリnon-SARGable 、しかし、そうするための最も簡単な方法は(コメントで提案された Edgar として):

WHERE LOWER(Name) LIKE '%hospitalist%' 

または

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