Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

SQL Server Like Query não diferencia maiúsculas de minúsculas


Problema:

Causa:a coluna 'Nome' não diferencia maiúsculas de minúsculas (CI ) colação.

Solução:Você tem que usar um CS collation:SELECT * FROM fn_helpcollations() WHERE description LIKE N'%case-sensitive%' .

Observação:há um agrupamento de banco de dados e um agrupamento em nível de coluna. E, há, também, um agrupamento de nível 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
*/

Simplesmente alterar o agrupamento do banco de dados NÃO altere o agrupamento para tabelas e colunas de usuários existentes:

Fonte

Após alterar o agrupamento do banco de dados , a saída das consultas acima será:
/*
DatabaseCollation -- changed
----------------------------
SQL_Latin1_General_CP1_CS_AS
*/

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

e, como você pode ver, o agrupamento da coluna Name permanece CI.

Além disso, alterar o agrupamento do banco de dados afetará apenas as novas tabelas e colunas criadas. Assim, alterar o agrupamento do banco de dados pode gerar resultados estranhos (na minha opinião ) porque alguns [N][VAR]CHAR colunas serão CI e as novas colunas serão CS.

Solução detalhada nº 1:se apenas algumas consultas para a coluna Name precisa ser CS então vou reescrever WHERE cláusula dessas consultas assim:
SELECT  Name 
FROM    dbo.Table_2
WHERE   Name LIKE 'Joe' AND Name LIKE 'Joe' COLLATE SQL_Latin1_General_CP1_CS_AS



Isso dará uma alteração no SQL Server para fazer um Index Seek na coluna Name (há um índice na coluna Name ). Além disso, o plano de execução incluirá uma conversão implícita (consulte Predicate propriedade para Index Seek ) devido ao seguinte predicado Name = N'Joe' COLLATE SQL_Latin1_General_CP1_CS_AS .

Solução detalhada nº 2:se todas as consultas para a coluna Name precisa ser CS, então vou alterar o agrupamento apenas para a coluna Name portanto:
-- 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'