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?
Você pode anexar um novo agrupamento à sua consulta de seleção para encontrar maiúsculas ou minúsculas.
-- Case sensitive exampleSELECT*FROMTABLEWHERE Name collate SQL_Latin1_General_CP1_CS_AS like'%hospitalist%'-- Case insensitive exampleSELECT*FROMTABLEWHERE 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.
@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*FROMTABLEWHERE Name LIKE'[hH][oO][sS][pP][iI][tT][aA][lL][iI][sS][tT]%'
CREATETABLE#tmp_cohellation_fun
(
ID INT IDENTITY(1,1)PRIMARYKEYCLUSTERED, myValue VARCHAR(50)COLLATE SQL_Latin1_General_CP1_CS_AS
)-- Garbage values to represent data you don't wantINSERTINTO#tmp_cohellation_fun
SELECT CAST(NEWID()AS VARCHAR(50))FROM master.sys.configurations t1
CROSSJOIN master.sys.configurations t2
CROSSJOIN master.sys.configurations t3;-- Sprinkle a little bit of good dataINSERTINTO#tmp_cohellation_fun
(myValue)VALUES('Apple'),('apple')-- Another healthy helping of garbage that we don't care aboutINSERTINTO#tmp_cohellation_fun
SELECT CAST(NEWID()AS VARCHAR(50))FROM master.sys.configurations t1
CROSSJOIN master.sys.configurations t2
CROSSJOIN master.sys.configurations t3;-- Some more good dataINSERTINTO#tmp_cohellation_fun
(myValue)VALUES('aPple'),('APPLE'),('APple')-- Final insert of garbage that we don't care aboutINSERTINTO#tmp_cohellation_fun
SELECT CAST(NEWID()AS VARCHAR(50))FROM master.sys.configurations t1
CROSSJOIN master.sys.configurations t2
CROSSJOIN master.sys.configurations t3
;-- Create a nonclustered rowstore indexCREATEINDEX ix_myValue ON#tmp_cohellation_fun (myValue);SETSTATISTICSXMLON;-- Seek, but incorrect resultsSELECT*FROM#tmp_cohellation_fun
WHERE myValue LIKE'apple%';-- Scan, with correct resultsSELECT*FROM#tmp_cohellation_fun
WHERE myValue COLLATE SQL_Latin1_General_CP1_CI_AS LIKE'apple%';-- Seek, with correct resultsSELECT*FROM#tmp_cohellation_fun
WHERE myValue LIKE'[aA][pP][pP][lL][eE]%';SETSTATISTICSXMLOFF;DROPTABLEIFEXISTS#tmp_cohellation_fun
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.
select
tempo. 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 serSELECT * FROM TABLE WHERE VALUE LIKE %hospitalist
ouSELECT * 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.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:
Este exemplo ( link dbfiddle aqui ) mostra melhor o que quero dizer:
fonte
Isso e a
COLLATE
resposta 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) é:ou
fonte