Non sembra che ciò possa essere risolto in T-SQL puro poiché CHARINDEX
né PATINDEX
consentire né utilizzare più di 8000 byte nella stringa "cercare" (ovvero un massimo di 8000 VARCHAR
o 4000 NVARCHAR
caratteri). Questo può essere visto nei seguenti test:
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
Entrambe queste query restituiscono il seguente errore:
Messaggio 8152, livello 16, stato 10, riga xxxxx
Dati troncati o binari verrebbero troncati.
E, riducendo l'una 7000
o l' altra di quelle query fino a 3999
eliminare l'errore. In 4000
entrambi i casi verrà inoltre visualizzato un errore (a causa del N'Z'
carattere aggiuntivo all'inizio).
TUTTAVIA, ciò può essere realizzato usando SQLCLR. È abbastanza semplice creare una funzione scalare che accetta due parametri di input di tipoNVARCHAR(MAX)
.
L'esempio seguente illustra questa capacità usando la versione gratuita della libreria SQL # SQLCLR (che ho creato, ma String_Contains è di nuovo disponibile nella versione gratuita :-).
L' UDF scalare String_Contains attualmente ha il @SearchValue
parametro di input come NVARCHAR(4000)
invece di NVARCHAR(MAX)
(non devo aver pensato che le persone sarebbero alla ricerca di stringhe di oltre 4000 caratteri ;-) ma è molto facile da cambiare apportando la seguente modifica una tantum (dopo SQL # è stato installato, ovviamente):
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
IMPOSTARE
-- 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;
PROVE
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
Tieni presente che String_Contains sta utilizzando un confronto tutto sensibile (maiuscolo / minuscolo, accento, Kana e larghezza).
where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'