看来这不可能在纯T-SQL中解决,因为在“搜索”字符串中(即最多8000个或4000个字符),CHARINDEX
也PATINDEX
不允许使用超过8000个字节。在以下测试中可以看到:VARCHAR
NVARCHAR
SELECT 1 WHERE CHARINDEX(N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 7000),
N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 6000)) > 0
SELECT 1 WHERE PATINDEX(N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 7000),
N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 6000)) > 0
这些查询都返回以下错误:
消息8152,级别16,状态10,行xxxxx
字符串或二进制数据将被截断。
并且,减少7000
这些查询中的任何一个以3999
消除错误。4000
两种情况下的值也都会错误(由于N'Z'
开头有多余的字符)。
但是,可以使用SQLCLR完成此操作。创建一个接受两个类型为的输入参数的标量函数非常简单NVARCHAR(MAX)
。
以下示例使用SQL# SQLCLR库的免费版本(我创建了该版本,但String_Contains在免费版本中再次可用:-)说明了此功能。
设定
-- DROP TABLE #ContainsData;
CREATE TABLE #ContainsData
(
ContainsDataID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
Col1 NVARCHAR(MAX) NOT NULL
);
INSERT INTO #ContainsData ([Col1])
VALUES (N'Q' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 15000)),
(N'W' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 20000)),
(N'Z' + REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 70000));
-- verify the lengths being over 8000
SELECT tmp.[ContainsDataID], tmp.[Col1], DATALENGTH(tmp.[Col1])
FROM #ContainsData tmp;
测试
SELECT tmp.[ContainsDataID], tmp.[Col1], DATALENGTH(tmp.[Col1])
FROM #ContainsData tmp
WHERE SQL#.String_Contains(tmp.[Col1], REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 15100)) = 1;
-- IDs returned: 2 and 3
SELECT tmp.[ContainsDataID], tmp.[Col1], DATALENGTH(tmp.[Col1])
FROM #ContainsData tmp
WHERE SQL#.String_Contains(tmp.[Col1], REPLICATE(CONVERT(NVARCHAR(MAX), N'a'), 26100)) = 1;
-- IDs returned: 3
请记住,String_Contains使用的是对所有内容敏感的(大小写,重音,假名和宽度)比较。
where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'