Dường như điều này không thể giải quyết được bằng T-SQL thuần túy vì CHARINDEX
cũng không PATINDEX
cho phép sử dụng hơn 8000 byte trong chuỗi "để tìm kiếm" (tức là tối đa 8000 VARCHAR
hoặc 4000 NVARCHAR
ký tự). Điều này có thể được nhìn thấy trong các thử nghiệm sau:
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
Cả hai truy vấn đó đều trả về lỗi sau:
Msg 8152, Cấp 16, Trạng thái 10,
Chuỗi xxxxx hoặc dữ liệu nhị phân sẽ bị cắt ngắn.
Và, giảm một 7000
trong hai truy vấn đó để 3999
thoát khỏi lỗi. Giá trị 4000
trong cả hai trường hợp cũng sẽ bị lỗi (do N'Z'
ký tự phụ ở đầu).
TUY NHIÊN, điều này có thể được thực hiện bằng SQLCLR. Nó khá đơn giản để tạo một hàm vô hướng chấp nhận hai tham số đầu vào loại NVARCHAR(MAX)
.
Ví dụ sau minh họa khả năng này bằng phiên bản Miễn phí của thư viện SQL # SQLCLR (mà tôi đã tạo, nhưng String_Contains lại có sẵn trong phiên bản Miễn phí :-).
Các String_Contains vô hướng UDF hiện có @SearchValue
param đầu vào như NVARCHAR(4000)
thay vì NVARCHAR(MAX)
(tôi phải không có suy nghĩ mọi người sẽ được tìm kiếm cho chuỗi hơn 4000 ký tự ;-) nhưng đó là rất dễ dàng để thay đổi bằng cách thay đổi một lần sau (sau khi SQL # đã được cài đặt, tất nhiên):
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
THIẾT LẬP
-- 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;
KIỂM TRA
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
Xin lưu ý rằng String_Contains đang sử dụng so sánh mọi thứ nhạy cảm (trường hợp, dấu, Kana và chiều rộng).
where st.text like '%MY_QUERY%CHARS%' ESCAPE '?'