Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Sử dụng T-SQL, trả về phần tử được phân tách thứ n từ một chuỗi

Đâ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_VALUEOPENJSON .

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Khóa ngoài cho khóa không phải khóa chính

  2. 3 cách trả về hàng chứa ký tự chữ và số trong SQL Server

  3. Đăng nhập không thành công cho người dùng 'DOMAIN \ MACHINENAME $'

  4. Làm cách nào để xác định trong SQL Server nếu một phạm vi dateTime chồng lên một phạm vi khác

  5. Thêm cột bảng mới vào vị trí thứ tự cụ thể trong Microsoft SQL Server