Похоже, что это не может быть решено в чистом T-SQL, так как не позволяет и CHARINDEX
не PATINDEX
позволяет использовать более 8000 байтов в строке «для поиска» (т. Е. Не более 8000 VARCHAR
или 4000 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 снова доступен в бесплатной версии :-).
String_Contains скалярных UDF в настоящее время имеют @SearchValue
вход параметры , как NVARCHAR(4000)
вместо того , чтобы NVARCHAR(MAX)
(я не должен подумать , люди будут искать для строк более 4000 символов ;-) но это очень легко изменить, сделав следующее изменение одноразового (после SQL # было установлено, конечно):
GO
ALTER FUNCTION [SQL#].[String_Contains](@StringValue [NVARCHAR](MAX),
@SearchValue [NVARCHAR](MAX))
RETURNS [BIT]
WITH EXECUTE AS CALLER
AS EXTERNAL NAME [SQL#].[STRING].[Contains];
GO
НАСТРОИТЬ
-- 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 '?'