Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using TSQL, CAST() with COLLATE is non-deterministic. How to make it deterministic? What is the work-around?

I have a function that includes:

SELECT @pString = CAST(@pString AS VARCHAR(255)) COLLATE SQL_Latin1_General_Cp1251_CS_AS

This is useful, for example, to remove accents in french; for example:

UPPER(CAST('Éléctricité' AS VARCHAR(255)) COLLATE SQL_Latin1_General_Cp1251_CS_AS)

gives ELECTRICITE.

But using COLLATE makes the function non-deterministic and therefore I cannot use it as a computed persisted value in a column.

Q1. Is there another (quick and easy) way to remove accents like this, with a deterministic function?

Q2. (Bonus Question) The reason I do this computed persisted column is to search. For example the user may enter the customer's last name as either 'Gagne' or 'Gagné' or 'GAGNE' or 'GAGNÉ' and the app will find it using the persisted computed column. Is there a better way to do this?

EDIT: Using SQL Server 2012 and SQL-Azure.

like image 405
Frank Monroe Avatar asked Oct 02 '13 02:10

Frank Monroe


2 Answers

You will find that it is in fact deterministic, it just has different behavior depending on the character you're trying to collate.

Check the page for Windows 1251 encoding for behavior on accepted characters, and unacceptable characters.

Here is a collation chart for Cyrillic_General_CI_AI. This is codepage 1251 Case Insensitive and Accent Insensitive. This will show you the mappings for all acceptable characters within this collation.

As for the search question, as Keith said, I would investigate putting a full text index on the column you are going to be searching on.

like image 58
Codeman Avatar answered Oct 16 '22 19:10

Codeman


The best answer I got was from Sebastian Sajaroff. I used his example to fix the issue. He suggested a VIEW with a UNIQUE INDEX. This gives a good idea of the solution:

create table Test(Id int primary key, Name varchar(20))
create view TestCIAI with schemabinding as
select ID, Name collate SQL_Latin1_General_CP1_CI_AI as NameCIAI from Test 
create unique clustered index ix_Unique on TestCIAI (Id)
create unique nonclustered index ix_DistinctNames on TestCIAI (NameCIAI)
insert into Test values (1, 'Sébastien')
--Insertion 2 will fail because of the unique nonclustered indexed on the view 
--(which is case-insensitive, accent-insensitive)
insert into Test values (2, 'Sebastien')
like image 23
Frank Monroe Avatar answered Oct 16 '22 18:10

Frank Monroe