This is useful when you want to have an easy control on case insensitiveness. That is, use a flag to set it ON or OFF.
The difficulty of having conditional COLLATE is that SQL Server applies a COLLATE statement to the entire clause. For example, if there's one COLLATE within a CASE, it will be applied to the entire CASE and trying to use different COLLATE statements will raise a conflict error.
It's also not possible to specify the COLLATE value as a variable unless you use dynamic SQL.
So here's my answer to this problem:
declare
@ignoreCase BIT
= 1
declare
@pattern VARCHAR(max)
= '%featureconfig%'
SELECT
Name, SUBSTRING(
Script,
CASE WHEN
@ignoreCase = 1 THEN
PATINDEX(@pattern, Script
COLLATE Latin1_General_CI_AI)
ELSE 0 END
+
CASE WHEN
@ignoreCase = 0 THEN
PATINDEX(@pattern, Script
COLLATE Latin1_General_CS_AI)
ELSE 0 END
- 90,
/* Start showing 90 characters before match, for context */
LEN(Script)
)
FROM TableWithNameAndScriptHere
WHERE 1
= 0 /* bogus FALSE condition to ease adding or removing "OR" clauses */
OR (@ignoreCase
= 1 AND
(script
like @pattern
COLLATE Latin1_General_CI_AI))
OR (@ignoreCase
= 0 AND
(script
like @pattern
COLLATE Latin1_General_BIN))
order
by Name
The correct CASE will result in the index where the pattern first matches, whereas the incorrect CASE will result in 0. The two can then be added up so that their applicability can be interchanged by the @ignoreCase variable.
The WHERE clause itself only needs different LIKE conditions for each COLLATE.
Easy enough.

No comments:
Post a Comment