Menggunakan SQL Server, bagaimana cara membagi string sehingga saya dapat mengakses item x?
Ambil string "Hello John Smith". Bagaimana saya bisa membagi string dengan ruang dan mengakses item di indeks 1 yang seharusnya mengembalikan "John"?
sql
sql-server
tsql
split
GateKiller
sumber
sumber
Jawaban:
Anda dapat menemukan solusi dalam Fungsi Ditentukan Pengguna SQL untuk Parse a Delimited String bermanfaat (dari Proyek Kode ).
Anda dapat menggunakan logika sederhana ini:
sumber
SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( RTRIM( LTRIM( @p_SourceText)))
dan tidakSET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( @p_SourceText)
?STRING_SPLIT
yang akan membagi string dan mengembalikan hasil tabel satu kolom yang bisa Anda gunakan dalamSELECT
pernyataan atau di tempat lain.Saya tidak percaya SQL Server memiliki fungsi split bawaan, jadi selain UDF, satu-satunya jawaban lain yang saya tahu adalah membajak fungsi PARSENAME:
PARSENAME mengambil string dan membaginya pada karakter periode. Dibutuhkan angka sebagai argumen kedua, dan angka itu menentukan segmen string mana yang akan kembali (bekerja dari belakang ke depan).
Masalah yang jelas adalah ketika string sudah mengandung tanda titik. Saya masih berpikir menggunakan UDF adalah cara terbaik ... ada saran lain?
sumber
SPLIT()
fungsi ini tidak disertakan karena mendorong desain database miskin, dan database akan pernah dioptimalkan untuk menggunakan data yang disimpan dalam format ini. RDBMS tidak berkewajiban membantu pengembang melakukan hal-hal bodoh yang telah dirancang untuk tidak ditangani. Jawaban yang benar akan selalu "Menormalkan database Anda seperti yang kami katakan 40 tahun yang lalu." SQL atau RDBMS tidak dapat disalahkan untuk desain yang buruk.Pertama, buat fungsi (menggunakan CTE, ekspresi tabel umum tidak jauh dengan kebutuhan untuk tabel temp)
Kemudian, gunakan sebagai tabel apa saja (atau modifikasi agar sesuai dengan proc tersimpan Anda yang sudah ada) seperti ini.
Memperbarui
Versi sebelumnya akan gagal untuk string input yang lebih panjang dari 4000 karakter. Versi ini menangani batasan:
Penggunaannya tetap sama.
sumber
100
(untuk mencegah infinite loop). Gunakan petunjuk MAXRECURSION untuk menentukan jumlah level rekursi (0
to32767
,0
adalah "no limit" - dapat menghancurkan server). BTW, jawabannya jauh lebih baik daripadaPARSENAME
, karena itu universal :-). +1maxrecursion
ke solusi ini perlu diingat pertanyaan ini dan jawabannya Bagaimana mengaturmaxrecursion
opsi untuk CTE di dalam Table-Valued-Function .s
tidak lagi ditentukanSebagian besar solusi di sini digunakan saat loop atau CTE rekursif. Pendekatan berbasis set akan lebih unggul, saya janji, jika Anda dapat menggunakan pembatas selain spasi:
Penggunaan sampel:
Hasil:
Anda juga bisa menambahkan yang
idx
Anda inginkan sebagai argumen ke fungsi, tetapi saya akan membiarkannya sebagai latihan bagi pembaca.Anda tidak dapat melakukan ini hanya dengan fungsi asli yang
STRING_SPLIT
ditambahkan di SQL Server 2016, karena tidak ada jaminan bahwa output akan diberikan dalam urutan daftar asli. Dengan kata lain, jika Anda lulus dalam3,6,1
hasil kemungkinan akan berada di urutan itu, tetapi bisa jadi1,3,6
. Saya telah meminta bantuan komunitas dalam meningkatkan fungsi bawaan di sini:Dengan umpan balik kualitatif yang cukup , mereka mungkin benar-benar mempertimbangkan untuk membuat beberapa peningkatan ini:
Lebih lanjut tentang fungsi split, mengapa (dan buktikan itu) sementara loop dan CTE rekursif tidak skala, dan alternatif yang lebih baik, jika memisahkan string yang berasal dari lapisan aplikasi:
Pada SQL Server 2016 atau lebih baru, Anda harus melihat
STRING_SPLIT()
danSTRING_AGG()
:sumber
select * from DBO.SplitString('Hello John smith', ' ');
dan output yang dihasilkan adalah: Nilai Halo ello llo lo o John ohn hn n smith mith ith th hAnda bisa memanfaatkan tabel angka untuk melakukan penguraian string.
Buat tabel angka fisik:
Buat tabel uji dengan 10.00000 baris
Buat fungsinya
Penggunaan (menghasilkan 3mil baris dalam 40-an di laptop saya)
membersihkan
Performa di sini tidak luar biasa, tetapi memanggil fungsi lebih dari satu juta tabel baris bukanlah ide terbaik. Jika melakukan split string pada banyak baris saya akan menghindari fungsi.
sumber
desc
sudah dihapus?REVERSE(PARSENAME(REPLACE(REVERSE('Hello John Smith'), ' ', '.'), 1))
dari @NothingsImpossible diselesaikan dalam 1,5 menit. @hello_earth Bagaimana solusi Anda membandingkan string yang lebih panjang dengan lebih dari 4 bidang?Pertanyaan ini bukan tentang pendekatan string split , tetapi tentang bagaimana mendapatkan elemen ke-n .
Semua jawaban di sini sedang melakukan semacam pemisahan string menggunakan rekursi,
CTE
s, banyakCHARINDEX
,REVERSE
danPATINDEX
, menciptakan fungsi, panggilan untuk metode CLR, tabel angka,CROSS APPLY
s ... Sebagian besar jawaban mencakup banyak baris kode.Tetapi - jika Anda benar - benar menginginkan tidak lebih dari sebuah pendekatan untuk mendapatkan elemen ke-n - ini dapat dilakukan sebagai one-liner nyata , tanpa UDF, bahkan bukan sub-pilih ... Dan sebagai manfaat tambahan: ketik aman
Dapatkan bagian 2 dibatasi oleh spasi:
Tentu saja Anda dapat menggunakan variabel untuk pembatas dan posisi (gunakan
sql:column
untuk mengambil posisi secara langsung dari nilai kueri):Jika string Anda mungkin menyertakan karakter terlarang (terutama satu di antaranya
&><
), Anda masih bisa melakukannya dengan cara ini. Cukup gunakanFOR XML PATH
pada string Anda terlebih dahulu untuk mengganti semua karakter terlarang dengan urutan pelepasan yang sesuai secara implisit.Ini adalah kasus yang sangat istimewa jika - tambahan - pembatas Anda adalah titik koma . Dalam hal ini saya mengganti pembatas pertama ke '# DLMT #', dan akhirnya ganti ini dengan tag XML:
PEMBARUAN untuk SQL-Server 2016+
Dengan menyesal para pengembang lupa untuk mengembalikan indeks bagian itu
STRING_SPLIT
. Tapi, menggunakan SQL-Server 2016+, adaJSON_VALUE
danOPENJSON
.Dengan
JSON_VALUE
kita dapat lewat di posisi sebagai array indeks.Untuk
OPENJSON
itu dokumentasi menyatakan dengan jelas:Sebuah string seperti
1,2,3
kebutuhan tidak lebih dari kurung:[1,2,3]
.Sederetan kata-kata seperti
this is an example
perlu["this","is","an","example"]
.Ini adalah operasi string yang sangat mudah. Coba saja:
- Lihat ini untuk pemisah tali yang aman ( berbasis nol ):
Dalam posting ini saya menguji berbagai pendekatan dan menemukan, itu
OPENJSON
sangat cepat. Bahkan jauh lebih cepat daripada metode "delimitedSplit8k ()" yang terkenal ...UPDATE 2 - Dapatkan nilai-nilai yang aman
Kita bisa menggunakan array dalam array hanya dengan menggunakan doubled
[[]]
. Ini memungkinkan untuk sebuahWITH
klausa yang diketik :sumber
<x><![CDATA[x<&>x]]></x>
.CDATA
-bagian bisa menangani ini juga ... Tapi setelah para pemain mereka pergi (diubah menjadi melarikan diritext()
secara implisit). Saya tidak suka sihir di bawah tenda , jadi saya lebih suka(SELECT 'Text with <&>' AS [*] FOR XML PATH(''))
pendekatan -. Ini terlihat lebih bersih bagi saya dan tetap terjadi ... (Lebih banyak tentang CDATA dan XML ).Inilah UDF yang akan melakukannya. Ini akan mengembalikan tabel nilai yang dibatasi, belum mencoba semua skenario di atasnya tetapi contoh Anda berfungsi dengan baik.
Anda akan menyebutnya seperti ini:
Sunting: Solusi yang diperbarui untuk menangani pembatas dengan len> 1 seperti pada:
sumber
Di sini saya memposting cara solusi sederhana
Jalankan fungsi seperti ini
sumber
Menurut pendapat saya kalian membuatnya terlalu rumit. Cukup buat CLR UDF dan lakukan saja.
sumber
Bagaimana dengan penggunaan
string
danvalues()
pernyataan?Hasil-set tercapai.
sumber
Saya menggunakan jawaban frederic tetapi ini tidak berhasil di SQL Server 2005
Aku diubah dan saya menggunakan
select
denganunion all
dan bekerjaDan hasil-set adalah:
sumber
EXEC
.EXEC
secara implisit memanggil prosedur tersimpan, dan Anda tidak dapat menggunakan prosedur tersimpan di UDF.Pola ini berfungsi dengan baik dan Anda dapat menggeneralisasi
perhatikan BIDANG , INDEKS dan JENIS .
Biarkan beberapa tabel dengan pengenal suka
Lalu, Anda bisa menulis
membelah dan casting semua bagian.
sumber
Jika database Anda memiliki tingkat kompatibilitas 130 atau lebih tinggi maka Anda dapat menggunakan fungsi STRING_SPLIT bersama dengan klausa OFFSET FETCH untuk mendapatkan item tertentu dengan indeks.
Untuk mendapatkan item pada indeks N (berbasis nol), Anda dapat menggunakan kode berikut
Untuk memeriksa tingkat kompatibilitas basis data Anda , jalankan kode ini:
sumber
xml
pendekatan berbasis-duduk, karena memungkinkan untuk mengambil tipe nilai-aman dan tidak perlu sub-permintaan, tapi ini adalah bagus +1 dari sisi sayaSTRING_SPLIT
tuntutan untuk v2016 +. Dalam hal ini lebih baik menggunakanOPENJSON
atauJSON_VALUE
. Anda mungkin ingin memeriksa jawaban sayaSaya mencari solusi di internet dan di bawah ini berfungsi untuk saya. Ref .
Dan Anda memanggil fungsi seperti ini:
sumber
Namun bagian lain dari string dengan fungsi delimeter:
dan penggunaannya:
yang mengembalikan:
sumber
Coba ini:
Uji seperti ini:
sumber
Contoh berikut menggunakan CTE rekursif
Perbarui 18.09.2013
Demo di SQLFiddle
sumber
sumber
Anda dapat membagi string dalam SQL tanpa membutuhkan fungsi:
Jika Anda perlu mendukung string acak (dengan karakter khusus xml)
sumber
Saya tahu ini adalah pertanyaan lama, tetapi saya pikir seseorang dapat mengambil manfaat dari solusi saya.
SQL FIDDLE
Keuntungan:
Keterbatasan:
Catatan : solusinya dapat memberikan sub-string hingga N.
Untuk mengatasi batasan kita dapat menggunakan referensi berikut .
Tetapi sekali lagi solusi di atas tidak dapat digunakan dalam sebuah tabel (Actaully saya tidak dapat menggunakannya).
Sekali lagi saya berharap solusi ini dapat membantu seseorang.
Pembaruan: Dalam hal Catatan> 50000 tidak disarankan untuk digunakan
LOOPS
karena akan menurunkan Kinerjasumber
Solusi berbasis set murni menggunakan
TVF
dengan rekursifCTE
. Anda bisaJOIN
danAPPLY
fungsi ini untuk dataset apa pun.Pemakaian:
Hasil:
sumber
Hampir semua jawaban lain menggantikan string yang sedang dibagi yang membuang siklus CPU dan melakukan alokasi memori yang tidak perlu.
Saya membahas cara yang jauh lebih baik untuk melakukan pemisahan string di sini: http://www.digitalruby.com/split-string-sql-server/
Ini kodenya:
sumber
Solusi CTE rekursif dengan nyeri server, ujilah
Setup Skema MS SQL Server 2008 :
Pertanyaan 1 :
Hasil :
sumber
sementara mirip dengan jawaban berbasis xml oleh josejuan, saya menemukan bahwa memproses jalur xml hanya sekali, kemudian pivoting cukup efisien:
berlari jam 8:30
berlari di 9:20
sumber
DAN GUNAKAN ITU
sumber
jika ada yang ingin mendapatkan hanya satu bagian dari teks terpisah dapat menggunakan ini
pilih * dari fromSplitStringSep ('Word1 wordr2 word3', '')
sumber
Saya memindahkan ini,
satu-satunya perhatian yang harus Anda perhatikan adalah titik '.' ujung @x harus selalu ada di sana.
sumber
membangun pada @NothingsImpossible solusi, atau, lebih tepatnya, mengomentari jawaban yang paling banyak dipilih (tepat di bawah yang diterima), saya menemukan solusi cepat dan kotor berikut memenuhi kebutuhan saya sendiri - itu memiliki manfaat hanya berada dalam domain SQL.
diberi string "pertama; kedua; ketiga; keempat; kelima", katakan, saya ingin mendapatkan token ketiga. ini bekerja hanya jika kita tahu berapa banyak token yang akan dimiliki string - dalam kasus ini 5., jadi cara tindakan saya adalah memotong dua token terakhir (permintaan dalam), dan kemudian memotong dua token pertama pergi ( permintaan luar)
saya tahu bahwa ini jelek dan mencakup kondisi spesifik saya, tetapi saya mempostingnya kalau-kalau ada yang merasa berguna. Bersulang
sumber
sumber
Dimulai dengan SQL Server 2016 kami string_split
sumber
STRING_SPLIT
tidak menjamin untuk mengembalikan pesanan yang sama. TapiOPENJSON
apakah (lihat jawaban saya (bagian pembaruan) )