Parece que isso não pode ser resolvido no T-SQL puro, pois CHARINDEX
nem PATINDEX
permite o uso de mais de 8000 bytes na string "procurar" (ou seja, no máximo 8000 VARCHAR
ou 4000 NVARCHAR
caracteres). Isso pode ser visto nos seguintes testes:
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
Ambas as consultas retornam o seguinte erro:
A mensagem 8152, nível 16, estado 10, linha xxxxx
Seqüência de caracteres ou dados binários seria truncada.
Além disso, reduzir o número 7000
de consultas para 3999
eliminar o erro. Um valor de 4000
ambos os casos também apresentará erro (devido ao N'Z'
caractere extra no início).
No entanto, isso pode ser feito usando o SQLCLR. É bastante simples criar uma função escalar que aceite dois parâmetros de entrada do tipo NVARCHAR(MAX)
.
O exemplo a seguir ilustra essa capacidade usando a versão gratuita do biblioteca SQL # SQLCLR (que eu criei, mas String_Contains está novamente disponível na versão Free :-).
O UDF escalar String_Contains atualmente possui o @SearchValue
parâmetro de entrada como em NVARCHAR(4000)
vez deNVARCHAR(MAX)
(I não deve ter pensado que as pessoas estariam procurando por cordas de mais de 4000 caracteres ;-) mas isso é muito fácil de mudança, fazendo a seguinte alteração de uma só vez (depois de SQL # foi instalado, é claro):
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
CONFIGURAÇÃO
-- 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;
TESTES
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
Lembre-se de que String_Contains está usando uma comparação sensível a tudo (maiúsculas e minúsculas, acento, Kana e largura).
where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'