sqlsql-servert-sqlcollate

Collate declared SQL variable


I've been looking at a query that looks for non-ASCII characters, reproduced below…

select line,
  patindex('%[^ !-~]%' COLLATE Latin1_General_BIN, Line) as [Position],
  substring(Line, patindex('%[^ !-~]%' COLLATE Latin1_General_BIN, Line), 1) as [InvalidCharacter],
  ascii(substring(line, patindex('%[^ !-~]%' COLLATE Latin1_General_BIN, Line), 1)) as [ASCIICode]
from staging.APARMRE1
where patindex('%[^ !-~]%' COLLATE Latin1_General_BIN, Line) > 0

…and it just strikes me that I'd want to declare a variable for '%[^ !-~]%' COLLATE Latin1_General_BIN instead of writing it out every time, but

declare @regex varchar(20) = '%[^ !-~]%' COLLATE Latin1_General_BIN;

select line,
  patindex(@regex, Line) as [Position],
  substring(Line, patindex(@regex, Line), 1) as [InvalidCharacter],
  ascii(substring(line, patindex(@regex, Line), 1)) as [ASCIICode]
from staging.APARMRE1
where patindex(@regex, Line) > 0

just doesn't do the same thing. Am I just missing some syntax? Is it impossible?


Solution

  • It is normal. When you create a variable it takes default collation for database.

    DECLARE @regex varchar(20) = '%[^ !-~]%' COLLATE Latin1_General_BIN;
    

    Your string with COLLATE Latin1_General_BIN is implicitly casted to string with your database default collation.


    For example database is Case-Insensitive. I use your syntax to create case-sensitive one and check metadata of it:

    DECLARE @v1 varchar(100) = 'ABC' COLLATE Latin1_General_CS_AS;
    
    SELECT name, collation_name
    FROM sys.dm_exec_describe_first_result_set(
        N'SELECT @v1 AS [@v1]', N'@v1 varchar(100)', 0);
    

    LiveDemo

    Output:

    ╔══════╦══════════════════════════════╗
    ║ name ║        collation_name        ║
    ╠══════╬══════════════════════════════╣
    ║ @v1  ║ SQL_Latin1_General_CP1_CI_AS ║
    ╚══════╩══════════════════════════════╝
    

    Variables(excluding columns in table variables) do not allow to define collation so there is no syntax like:

    DECLARE @v1 varchar(100) COLLATE Latin1_General_CS_AS = 'ABC' ;
    -- Incorrect syntax near the keyword 'COLLATE'.