Il ne semble pas que cela puisse être résolu en T-SQL pur car CHARINDEX
ni PATINDEX
autoriser ni utiliser plus de 8000 octets dans la chaîne "à rechercher" (c'est-à-dire max de 8000 VARCHAR
ou 4000 NVARCHAR
caractères). Cela peut être vu dans les tests suivants:
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
Ces deux requêtes renvoient l'erreur suivante:
Msg 8152, niveau 16, état 10, ligne xxxxx La
chaîne ou les données binaires seraient tronquées.
Et, la réduction de l'une 7000
ou l'autre de ces requêtes pour 3999
éliminer l'erreur. Une valeur de 4000
dans les deux cas entraînera également une erreur (en raison du N'Z'
caractère supplémentaire au début).
CEPENDANT, cela peut être accompli en utilisant SQLCLR. Il est assez simple de créer une fonction scalaire qui accepte deux paramètres d'entrée de type NVARCHAR(MAX)
.
L'exemple suivant illustre cette capacité en utilisant la version gratuite du bibliothèque SQL # SQLCLR (que j'ai créée, mais String_Contains est à nouveau disponible dans la version gratuite :-).
L' UDF scalaire String_Contains a actuellement le paramètre d'@SearchValue
entrée au NVARCHAR(4000)
lieu de NVARCHAR(MAX)
(je ne dois pas avoir pensé que les gens chercheraient des chaînes de plus de 4000 caractères ;-) mais c'est très facile à changer en effectuant le changement unique suivant (après SQL # a été installé, bien sûr):
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
INSTALLER
-- 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;
TESTS
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
Veuillez garder à l'esprit que String_Contains utilise une comparaison tout sensible (cas, accent, Kana et largeur).
where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'