Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

SQL Server Like Query non fa distinzione tra maiuscole e minuscole

Problema:

Causa:la colonna "Nome" non fa distinzione tra maiuscole e minuscole (CI ) confronto.

Soluzione:devi usare un CS confronto:SELECT * FROM fn_helpcollations() WHERE description LIKE N'%case-sensitive%' .

Nota:esistono regole di confronto database e regole di confronto a livello di colonna. E c'è anche un confronto a livello di server.

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
*/

La semplice modifica delle regole di confronto del database NON cambia le regole di confronto per le tabelle e le colonne utente esistenti:

Fonte

Dopo la modifica delle regole di confronto del database , l'output delle query precedenti sarà:

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

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

e, come puoi vedere, le regole di confronto della colonna Name rimane CI.

Inoltre, la modifica delle regole di confronto del database influirà solo sulle nuove tabelle e colonne create. Pertanto, la modifica delle regole di confronto del database potrebbe generare risultati strani (a mio opinione ) perché alcuni [N][VAR]CHAR le colonne saranno CI e le nuove colonne saranno CS.

Soluzione dettagliata n. 1:se solo alcune query per la colonna Name deve essere CS quindi riscriverò WHERE clausola di queste query così:

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

Questo darà una modifica a SQL Server per eseguire una Index Seek nella colonna Name (in c'è un indice sulla colonna Name ). Inoltre, il piano di esecuzione includerà una conversione implicita (vedi Predicate proprietà per Index Seek ) a causa del seguente predicato Name = N'Joe' COLLATE SQL_Latin1_General_CP1_CS_AS .

Soluzione dettagliata n. 2:se tutte le query per la colonna Name deve essere CS, quindi cambierò le regole di confronto solo per la colonna Name quindi:

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