sql >> Base de Datos >  >> RDS >> Sqlserver

SQL Server Like Query no distingue entre mayúsculas y minúsculas

Problema:

Causa:la columna 'Nombre' no distingue entre mayúsculas y minúsculas (CI ) colación.

Solución:Tienes que usar un CS intercalación:SELECT * FROM fn_helpcollations() WHERE description LIKE N'%case-sensitive%' .

Nota:Hay una intercalación de base de datos y una intercalación a nivel de columna. Y también hay una colación a nivel de servidor.

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

Simplemente cambiar la intercalación de la base de datos NO cambie la intercalación de las tablas y columnas de usuario existentes:

Fuente

Después de cambiar la intercalación de la base de datos , el resultado de las consultas anteriores será:

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

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

y, como puede ver la intercalación de la columna Name sigue siendo CI.

Además, cambiar la intercalación de la base de datos afectará solo a las nuevas tablas y columnas creadas. Por lo tanto, cambiar la intercalación de la base de datos podría generar resultados extraños (en mi opinión ) porque algunos [N][VAR]CHAR las columnas serán CI y las nuevas columnas serán CS.

Solución detallada n. ° 1:si solo algunas consultas para la columna Name necesita ser CS luego reescribiré WHERE cláusula de estas consultas así:

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

Esto dará un cambio a SQL Server para hacer una Index Seek en la columna Name (hay un índice en la columna Name ). Además, el plan de ejecución incluirá una conversión implícita (ver Predicate propiedad para Index Seek ) debido al siguiente predicado Name = N'Joe' COLLATE SQL_Latin1_General_CP1_CS_AS .

Solución detallada #2:si todas las consultas para la columna Name necesita ser CS, entonces cambiaré la intercalación solo para la columna Name así:

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