Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Menggunakan T-SQL, kembalikan elemen delimited ke-n dari sebuah string

Ini adalah jawaban termudah untuk mengambil 67 (type-safe!! ):

SELECT CAST('<x>' + REPLACE('1,222,2,67,888,1111',',','</x><x>') + '</x>' AS XML).value('/x[4]','int')

Berikut ini Anda akan menemukan contoh bagaimana menggunakan ini dengan variabel untuk string, pembatas dan posisi (bahkan untuk kasus tepi dengan karakter terlarang XML)

Yang mudah

Pertanyaan ini bukan tentang pendekatan pemisahan string , tetapi tentang cara mendapatkan elemen ke-n . Cara termudah dan sepenuhnya tidak dapat diluruskan adalah IMO ini:

Ini adalah one-liner asli untuk mendapatkan bagian 2 yang dibatasi oleh spasi:

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)')

Variabel dapat digunakan dengan sql:variable() atau sql:column()

Tentu saja Anda dapat menggunakan variabel untuk pembatas dan posisi (gunakan sql:column untuk mengambil posisi langsung dari nilai kueri):

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 dengan karakter terlarang XML

Jika string Anda mungkin menyertakan karakter terlarang , Anda masih bisa melakukannya dengan cara ini. Cukup gunakan FOR XML PATH pada string Anda terlebih dahulu untuk mengganti semua karakter terlarang dengan urutan escape yang pas secara implisit.

Ini adalah kasus yang sangat khusus jika - selain itu - pembatas Anda adalah titik koma . Dalam hal ini saya mengganti pembatas terlebih dahulu menjadi '#DLMT#', dan akhirnya mengganti ini dengan tag 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)');

PERBARUI untuk SQL-Server 2016+

Sayangnya pengembang lupa mengembalikan indeks bagian dengan STRING_SPLIT . Tapi, menggunakan SQL-Server 2016+, ada JSON_VALUE dan OPENJSON .

Dengan JSON_VALUE kita dapat meneruskan posisi sebagai array indeks.

Untuk OPENJSON dokumentasi menyatakan dengan jelas:

Saat OPENJSON mem-parsing larik JSON, fungsi mengembalikan indeks elemen dalam teks JSON sebagai kunci.

String seperti 1,2,3 hanya membutuhkan tanda kurung:[1,2,3] .
Rangkaian kata seperti this is an example harus ["this","is","an"," example"] .
Ini adalah operasi string yang sangat mudah. Coba saja:

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,']'));

--Lihat ini untuk pemisah string yang aman (berbasis nol ):

SELECT  JsonArray.[key] AS [Position]
       ,JsonArray.[value] AS [Part]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]') JsonArray

Dalam posting ini saya menguji berbagai pendekatan dan menemukan, bahwa OPENJSON benar-benar cepat. Bahkan jauh lebih cepat daripada metode "delimitedSplit8k()" yang terkenal...

PERBARUI 2 - Dapatkan nilai type-safe

Kita dapat menggunakan array di dalam array cukup dengan menggunakan [[]] dua kali lipat . Ini memungkinkan untuk mengetik WITH -klausa:

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. Jenis Kursor SQL Server - Kursor Dinamis | Tutorial SQL Server / Tutorial TSQL

  2. Hapus SKEMABINDING dari Tampilan di SQL Server

  3. Skrip Inventaris Koleksi SQL Server -1

  4. Kolom apa yang umumnya membuat indeks bagus?

  5. Tidak dapat menyelesaikan konflik pemeriksaan antara SQL_Latin1_General_CP1_CI_AS dan Latin1_General_CI_AS dalam operasi yang sama