¿Cómo hacer un LIKE insensible a mayúsculas y minúsculas en una base de datos sensible a mayúsculas y minúsculas?
11
Mi proveedor requiere que la base de datos del almacén de datos distinga entre mayúsculas y minúsculas, pero necesito hacer consultas que no distingan entre mayúsculas y minúsculas.
En una base de datos que distingue entre mayúsculas y minúsculas, ¿cómo escribiría esto para que no distinga entre mayúsculas y minúsculas?
Puede agregar una nueva clasificación a su consulta de selección para encontrar mayúsculas o 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%'
Solo tenga en cuenta los problemas de rendimiento que esto podría presentar. Deberá escanear el índice agrupado para ajustar / encontrar los valores cuando realice la clasificación. La forma en que está escribiendo la LIKEpieza también hace que la consulta no sea sargable.
@stom Hay dos métodos. Ya sea a) Mueva los problemas de rendimiento al tiempo de procesamiento y no al selecttiempo. Puede hacer esto creando una nueva columna con un subconjunto de los datos transformados y luego indexándolos, generalmente durante los momentos en que ejecutaría ETL. Esto tendría un costo de mantenimiento y no es un gran método. B) Puede hacer que la consulta de búsqueda sea discutible o sargable. Cambiar la consulta para que sea SELECT * FROM TABLE WHERE VALUE LIKE %hospitalisto SELECT * FROM TABLE WHERE VALUE LIKE hospitalist%funcionaría. Aparte de eso, está buscando hardware o características para aumentar la velocidad en un mal diseño.
Shaulinator
14
Si bien puede usar una función escalar como SUPERIOR o INFERIOR y puede volver a clasificar la columna para que ya no sea sensible a mayúsculas y minúsculas, todos estos enfoques requieren que la conversión de datos se realice contra los datos base, lo que nunca permitirá una búsqueda de índice. También está liderando su LIKE con un comodín, por lo que esto no es una gran preocupación para usted en este escenario de todos modos, pero si alguna vez quiso buscar la parte izquierda de una cadena de manera eficiente Y permitir el optimizador para buscar a través de un índice, puede especificar su cadena con corchetes ([]) de la siguiente manera:
SELECT*FROMTABLEWHERE Name LIKE'[hH][oO][sS][pP][iI][tT][aA][lL][iI][sS][tT]%'
Este ejemplo ( enlace dbfiddle aquí ) hace un mejor trabajo al mostrar lo que quiero decir:
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
Quiéralo. No puedo entender por qué SQL no puede simplemente retroceder con gracia como este cuando dice clasificar desde mayúsculas y minúsculas a mayúsculas y minúsculas, cuando tiene dos colaciones idénticas. Entiendo por qué no puedes ir para otro lado. De todos modos esto es algo bueno.
John Leidegren
13
Tanto esto como la COLLATErespuesta afectarán el rendimiento, ya que hacen que la consulta no sea SARGable , pero la forma más fácil de hacerlo (como sugirió Edgar en un comentario) es:
select
tiempo. Puede hacer esto creando una nueva columna con un subconjunto de los datos transformados y luego indexándolos, generalmente durante los momentos en que ejecutaría ETL. Esto tendría un costo de mantenimiento y no es un gran método. B) Puede hacer que la consulta de búsqueda sea discutible o sargable. Cambiar la consulta para que seaSELECT * FROM TABLE WHERE VALUE LIKE %hospitalist
oSELECT * FROM TABLE WHERE VALUE LIKE hospitalist%
funcionaría. Aparte de eso, está buscando hardware o características para aumentar la velocidad en un mal diseño.Si bien puede usar una función escalar como SUPERIOR o INFERIOR y puede volver a clasificar la columna para que ya no sea sensible a mayúsculas y minúsculas, todos estos enfoques requieren que la conversión de datos se realice contra los datos base, lo que nunca permitirá una búsqueda de índice. También está liderando su LIKE con un comodín, por lo que esto no es una gran preocupación para usted en este escenario de todos modos, pero si alguna vez quiso buscar la parte izquierda de una cadena de manera eficiente Y permitir el optimizador para buscar a través de un índice, puede especificar su cadena con corchetes ([]) de la siguiente manera:
Este ejemplo ( enlace dbfiddle aquí ) hace un mejor trabajo al mostrar lo que quiero decir:
fuente
Tanto esto como la
COLLATE
respuesta afectarán el rendimiento, ya que hacen que la consulta no sea SARGable , pero la forma más fácil de hacerlo (como sugirió Edgar en un comentario) es:o
fuente