Đây là câu trả lời dễ nhất để truy xuất số 67 ( loại an toàn !! ):
SELECT CAST('<x>' + REPLACE('1,222,2,67,888,1111',',','</x><x>') + '</x>' AS XML).value('/x[4]','int')
Trong phần sau, bạn sẽ tìm thấy các ví dụ về cách sử dụng điều này với các biến cho chuỗi, dấu phân cách và vị trí (ngay cả đối với các trường hợp cạnh có các ký tự bị cấm trong XML)
Cái dễ dàng
Câu hỏi này không phải về cách tiếp cận tách chuỗi , nhưng về cách lấy phần tử thứ n . Cách dễ nhất, hoàn toàn có thể nội dòng sẽ là IMO này:
Đây là một lớp lót thực sự để có được phần 2 được phân tách bằng dấu cách:
DECLARE @input NVARCHAR(100)=N'part1 part2 part3';
SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)')
Các biến có thể được sử dụng với sql:variable()
hoặc sql:column()
Tất nhiên bạn có thể sử dụng các biến cho dấu phân tách và vị trí (sử dụng sql:column
để truy xuất vị trí trực tiếp từ giá trị của truy vấn):
DECLARE @dlmt NVARCHAR(10)=N' ';
DECLARE @pos INT = 2;
SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)')
Edge-Case có các ký tự bị cấm trong XML
Nếu chuỗi của bạn có thể bao gồm các ký tự bị cấm , bạn vẫn có thể làm theo cách này. Chỉ cần sử dụng FOR XML PATH
trên chuỗi của bạn trước tiên để thay thế tất cả các ký tự bị cấm bằng trình tự thoát khớp hoàn toàn.
Đó là một trường hợp rất đặc biệt nếu - ngoài ra - dấu phân cách của bạn là dấu chấm phẩy . Trong trường hợp này, tôi thay thế dấu phân tách trước thành '# DLMT #', và cuối cùng thay thế dấu này thành các thẻ XML:
SET @input=N'Some <, > and &;Other äöü@€;One more';
SET @dlmt=N';';
SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)');
CẬP NHẬT cho SQL-Server 2016+
Rất tiếc, các nhà phát triển đã quên trả lại chỉ mục của phần bằng STRING_SPLIT
. Tuy nhiên, sử dụng SQL-Server 2016+, có JSON_VALUE
và OPENJSON
.
Với JSON_VALUE
chúng ta có thể chuyển vào vị trí là mảng của chỉ mục.
Đối với OPENJSON
tài liệu ghi rõ:
Khi OPENJSON phân tích cú pháp một mảng JSON, hàm trả về chỉ mục của các phần tử trong văn bản JSON dưới dạng khóa.
Một chuỗi như 1,2,3
không cần gì nhiều hơn ngoài dấu ngoặc:[1,2,3]
.
Một chuỗi các từ như this is an example
cần phải là ["this","is","an"," example"]
.
Đây là những thao tác với chuỗi rất dễ dàng. Chỉ cần dùng thử:
DECLARE @str VARCHAR(100)='Hello John Smith';
DECLARE @position INT = 2;
--We can build the json-path '$[1]' using CONCAT
SELECT JSON_VALUE('["' + REPLACE(@str,' ','","') + '"]',CONCAT('$[',@position-1,']'));
--Xem phần này để biết vị trí bộ chia chuỗi an toàn ( dựa trên không ):
SELECT JsonArray.[key] AS [Position]
,JsonArray.[value] AS [Part]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]') JsonArray
Trong bài đăng này, tôi đã thử nghiệm nhiều cách tiếp cận khác nhau và nhận thấy rằng OPENJSON
là thực sự nhanh chóng. Thậm chí còn nhanh hơn nhiều so với phương thức "delimitedSplit8k ()" nổi tiếng ...
CẬP NHẬT 2 - Nhận các giá trị kiểu an toàn
Chúng ta có thể sử dụng một mảng trong một mảng đơn giản bằng cách sử dụng [[]]
được nhân đôi . Điều này cho phép nhập WITH
-lời giải thích:
DECLARE @SomeDelimitedString VARCHAR(100)='part1|1|20190920';
DECLARE @JsonArray NVARCHAR(MAX)=CONCAT('[["',REPLACE(@SomeDelimitedString,'|','","'),'"]]');
SELECT @SomeDelimitedString AS TheOriginal
,@JsonArray AS TransformedToJSON
,ValuesFromTheArray.*
FROM OPENJSON(@JsonArray)
WITH(TheFirstFragment VARCHAR(100) '$[0]'
,TheSecondFragment INT '$[1]'
,TheThirdFragment DATE '$[2]') ValuesFromTheArray