これは純粋なT-SQLでは解決できCHARINDEX
ないPATINDEX
ようです。「検索する」文字列(つまり、最大8000 VARCHAR
または4000 NVARCHAR
文字)で8000バイト以上を使用できないためです。これは、次のテストで確認できます。
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を使用して実現できます。typeの2つの入力パラメーターを受け入れるスカラー関数を作成するのは非常に簡単NVARCHAR(MAX)
です。
次の例は、SQL# SQLCLRライブラリの無料版を使用してこの機能を示しています(私が作成しましたが、String_Containsは再び無料版で利用可能です:-)。
String_ContainsスカラーUDFは、現在持っている@SearchValue
ように、入力のparamをNVARCHAR(4000)
代わりにNVARCHAR(MAX)
(私は人々が検索されるだろうと思っていてはならないため、SQLの#の後に4000文字以上の文字列;-)それは、次の1回限りの変更を行うことにより、変化に非常に簡単です(もちろんインストールされています):
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 '?'