Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

SQL Server Like Query non sensible à la casse

Problème :

Cause :la colonne "Nom" contient un élément insensible à la casse (CI ) classement.

Solution :Vous devez utiliser un CS collation :SELECT * FROM fn_helpcollations() WHERE description LIKE N'%case-sensitive%' .

Remarque :Il existe un classement de base de données et un classement au niveau des colonnes. Et, il y a aussi un classement au niveau du serveur.

SELECT  DATABASEPROPERTYEX(DB_NAME(), 'Collation') AS DatabaseCollation
/*
-- Sample output (my database)
DatabaseCollation
----------------------------
SQL_Latin1_General_CP1_CI_AS
*/

SELECT  col.collation_name AS ColumnCollation
FROM    sys.columns col
WHERE   col.object_id = OBJECT_ID(N'dbo.Table_2') 
AND     col.name = N'Name'
/*
-- Sample output (my database)
ColumnCollation
----------------------------
SQL_Latin1_General_CP1_CI_AS
*/

Changer simplement le classement de la base de données ne sera PAS modifier le classement des tables et colonnes utilisateur existantes :

Source

Après modification du classement de la base de données , le résultat des requêtes ci-dessus sera :

/*
DatabaseCollation -- changed
----------------------------
SQL_Latin1_General_CP1_CS_AS
*/

/*
ColumnCollation -- no change
----------------------------
SQL_Latin1_General_CP1_CI_AS
*/

et, comme vous pouvez le voir, le classement de la colonne Name reste CI.

De plus, la modification du classement de la base de données n'affectera que les nouvelles tables et colonnes créées. Ainsi, la modification du classement de la base de données pourrait générer des résultats étranges (à mon opinion ) car certains [N][VAR]CHAR les colonnes seront CI et les nouvelles colonnes seront CS.

Solution détaillée #1 :si seulement quelques requêtes pour la colonne Name doit être CS alors je vais réécrire WHERE clause de ces requêtes :

SELECT  Name 
FROM    dbo.Table_2
WHERE   Name LIKE 'Joe' AND Name LIKE 'Joe' COLLATE SQL_Latin1_General_CP1_CS_AS

Cela donnera un changement à SQL Server pour faire une Index Seek sur la colonne Name (il y a un index sur la colonne Name ). De plus, le plan d'exécution inclura une conversion implicite (voir Predicate propriété pour Index Seek ) en raison du prédicat suivant Name = N'Joe' COLLATE SQL_Latin1_General_CP1_CS_AS .

Solution détaillée n° 2 :si toutes les requêtes portent sur la colonne Name besoin d'être CS alors je changerai le classement uniquement pour la colonne Name donc :

-- Drop all objects that depends on this column (ex. indexes, constraints, defaults)
DROP INDEX IX_Table_2_Name ON dbo.Table_2

-- Change column's collation
ALTER TABLE dbo.Table_2
ALTER COLUMN Name VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CS_AS
-- Replace VARCHAR(50) with proper data type and max. length
-- Replace COLLATE SQL_Latin1_General_CP1_CS_AS with the right CS collation

-- Recreate all objects that depends on column Name (ex. indexes, constraints, defaults)
CREATE INDEX IX_Table_2_Name ON dbo.Table_2 (Name)

-- Test query
SELECT  Name 
FROM    dbo.Table_2
WHERE   Name LIKE 'Joe'