Como executar um LIKE que não diferencia maiúsculas de minúsculas em um banco de dados que diferencia maiúsculas de minúsculas?

11

Meu fornecedor exige que o banco de dados do data warehouse faça distinção entre maiúsculas e minúsculas, mas preciso fazer consultas sem distinção entre maiúsculas e minúsculas.

Em um banco de dados com distinção entre maiúsculas e minúsculas, como você escreveria isso para não diferenciar maiúsculas de minúsculas?

    Where Name like '%hospitalist%'
James
fonte

Respostas:

17

Você pode anexar um novo agrupamento à sua consulta de seleção para encontrar maiúsculas ou minúsculas.

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

Esteja ciente dos problemas de desempenho que isso pode apresentar. Você precisará verificar o índice em cluster para ajustar / encontrar os valores ao executar o agrupamento. A maneira como você está escrevendo a LIKEpeça também torna a consulta não sargável.

Peguei o truque de agrupamento das aulas do SELECT Seminar de Kendra Little . Você pode encontrar informações adicionais sobre o agrupamento de Ben Snaidero, do MS SQL Tips.

MSDN ao agrupar.

Shaulinator
fonte
@stom Existem dois métodos. Ou a) Mova os problemas de desempenho para o tempo de processamento e não para o selecttempo. Você pode fazer isso criando uma nova coluna com um subconjunto dos dados transformados e depois indexá-los, normalmente durante os momentos em que você executaria o ETL. Isso teria um custo de manutenção e não é um ótimo método. B) Você pode tornar a pesquisa de consulta discutível ou sargável. Alterar a consulta para ser SELECT * FROM TABLE WHERE VALUE LIKE %hospitalistou SELECT * FROM TABLE WHERE VALUE LIKE hospitalist%funcionaria. Além disso, você está olhando para hardware ou recursos para aumentar a velocidade de um design ruim.
Shaulinator
14

Enquanto você pode usar uma função escalar como SUPERIOR ou INFERIOR e você pode re-ordenar a coluna de modo que ele não é mais sensível a maiúsculas, estas abordagens requerem conversão de dados ser feito em relação aos dados de base que nunca permitem uma busca de índice. Você também está liderando seu LIKE com um curinga, portanto, isso não é uma preocupação muito importante para você nesse cenário, mas se você quiser pesquisar a parte esquerda de uma string de maneira eficiente E permitir o otimizador para procurar por um índice, você pode especificar sua string com colchetes ([]) da seguinte maneira:

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

Este exemplo ( link dbfiddle aqui ) mostra melhor o que quero dizer:

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
fonte
Adoro. Está além de mim que o SQL não poderia simplesmente fazer o fallback gracioso quando você diz agrupar de maiúsculas e minúsculas para maiúsculas e minúsculas, quando você tem dois agrupamentos idênticos. Entendo por que você não pode ir para o outro lado. Enfim, isso é uma coisa boa.
John Leidegren
13

Isso e a COLLATEresposta afetarão o desempenho, devido ao fato de tornarem a consulta não SARGable , mas a maneira mais fácil de fazer isso (como Edgar sugeriu em um comentário) é:

WHERE LOWER(Name) LIKE '%hospitalist%' 

ou

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