Comment faire un LIKE insensible à la casse dans une base de données sensible à la casse?
11
Mon fournisseur exige que la base de données de l'entrepôt de données soit sensible à la casse, mais je dois lui faire des requêtes non sensibles à la casse.
Dans une base de données sensible à la casse, comment écririez-vous cela pour ne pas respecter la casse?
Vous pouvez ajouter un nouveau classement à votre requête de sélection pour trouver sensible à la casse ou insensible.
-- 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%'
Soyez juste conscient des problèmes de performances que cela pourrait présenter. Vous devrez analyser l'index cluster pour ajuster / trouver les valeurs lorsque vous effectuez le classement. La façon dont vous écrivez la LIKEpièce rend également la requête non discutable.
J'ai choisi l'astuce de collation des cours du séminaire SELECT de Kendra Little . Vous pouvez trouver des informations de classement supplémentaires auprès de Ben Snaidero dans MS SQL Tips.
@stom Il existe deux méthodes. Soit a) Déplacez les problèmes de performances vers le temps de traitement et non vers le selecttemps. Pour ce faire, créez une nouvelle colonne avec un sous-ensemble des données transformées, puis indexez-la, généralement pendant les périodes où vous exécutez ETL. Cela aurait un coût d'entretien et n'est pas une excellente méthode. B) Vous pouvez rendre la recherche de requête défendable ou discutable. Changer la requête pour qu'elle soit SELECT * FROM TABLE WHERE VALUE LIKE %hospitalistou SELECT * FROM TABLE WHERE VALUE LIKE hospitalist%fonctionnerait. En dehors de cela, vous recherchez du matériel ou des fonctionnalités pour augmenter la vitesse de mauvaise conception.
Shaulinator
14
Bien que vous puissiez utiliser une fonction scalaire telle que UPPER ou LOWER et que vous pouvez recalculer la colonne afin qu'elle ne soit plus sensible à la casse, ces approches nécessitent toutes une conversion des données par rapport aux données de base qui ne permettront jamais une recherche d'index. Vous dirigez également votre LIKE avec un caractère générique, donc ce n'est pas autant une préoccupation pour vous dans ce scénario de toute façon, mais si vous avez toujours voulu rechercher la partie gauche d'une chaîne de manière efficace ET autoriser l'optimiseur pour rechercher dans un index, vous pouvez spécifier votre chaîne avec des crochets ([]) comme suit:
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_funSELECT CAST(NEWID()AS VARCHAR(50))FROM master.sys.configurations t1CROSSJOIN master.sys.configurations t2CROSSJOIN 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_funSELECT CAST(NEWID()AS VARCHAR(50))FROM master.sys.configurations t1CROSSJOIN master.sys.configurations t2CROSSJOIN 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_funSELECT CAST(NEWID()AS VARCHAR(50))FROM master.sys.configurations t1CROSSJOIN master.sys.configurations t2CROSSJOIN master.sys.configurations t3;-- Create a nonclustered rowstore indexCREATEINDEX ix_myValue ON#tmp_cohellation_fun (myValue);SETSTATISTICSXMLON;-- Seek, but incorrect resultsSELECT*FROM#tmp_cohellation_funWHERE myValue LIKE'apple%';-- Scan, with correct resultsSELECT*FROM#tmp_cohellation_funWHERE myValue COLLATE SQL_Latin1_General_CP1_CI_AS LIKE'apple%';-- Seek, with correct resultsSELECT*FROM#tmp_cohellation_funWHERE myValue LIKE'[aA][pP][pP][lL][eE]%';SETSTATISTICSXMLOFF;DROPTABLEIFEXISTS#tmp_cohellation_fun
Aimer. Je ne comprends pas pourquoi SQL ne pouvait pas simplement se replier avec élégance comme ceci lorsque vous dites assembler de la casse à l'insensible à la casse, lorsque vous avez deux classements par ailleurs identiques. Je comprends pourquoi vous ne pouvez pas aller dans l'autre sens. Quoi qu'il en soit, ce sont de bonnes choses.
John Leidegren
13
Cela et la COLLATEréponse auront un impact sur les performances, car ils rendront la requête non SARGable , mais la façon la plus simple de le faire (comme Edgar l'a suggéré dans un commentaire) est:
select
temps. Pour ce faire, créez une nouvelle colonne avec un sous-ensemble des données transformées, puis indexez-la, généralement pendant les périodes où vous exécutez ETL. Cela aurait un coût d'entretien et n'est pas une excellente méthode. B) Vous pouvez rendre la recherche de requête défendable ou discutable. Changer la requête pour qu'elle soitSELECT * FROM TABLE WHERE VALUE LIKE %hospitalist
ouSELECT * FROM TABLE WHERE VALUE LIKE hospitalist%
fonctionnerait. En dehors de cela, vous recherchez du matériel ou des fonctionnalités pour augmenter la vitesse de mauvaise conception.Bien que vous puissiez utiliser une fonction scalaire telle que UPPER ou LOWER et que vous pouvez recalculer la colonne afin qu'elle ne soit plus sensible à la casse, ces approches nécessitent toutes une conversion des données par rapport aux données de base qui ne permettront jamais une recherche d'index. Vous dirigez également votre LIKE avec un caractère générique, donc ce n'est pas autant une préoccupation pour vous dans ce scénario de toute façon, mais si vous avez toujours voulu rechercher la partie gauche d'une chaîne de manière efficace ET autoriser l'optimiseur pour rechercher dans un index, vous pouvez spécifier votre chaîne avec des crochets ([]) comme suit:
Cet exemple ( lien dbfiddle ici ) montre mieux ce que je veux dire:
la source
Cela et la
COLLATE
réponse auront un impact sur les performances, car ils rendront la requête non SARGable , mais la façon la plus simple de le faire (comme Edgar l'a suggéré dans un commentaire) est:ou
la source