Bagaimana cara parameterisasi kueri yang berisi IN
klausa dengan sejumlah variabel argumen, seperti ini?
SELECT * FROM Tags
WHERE Name IN ('ruby','rails','scruffy','rubyonrails')
ORDER BY Count DESC
Dalam kueri ini, jumlah argumen bisa berkisar dari 1 hingga 5.
Saya lebih suka tidak menggunakan prosedur tersimpan khusus untuk ini (atau XML), tetapi jika ada beberapa cara elegan khusus untuk SQL Server 2008 , saya terbuka untuk itu.
sql
sql-server
parameters
Jeff Atwood
sumber
sumber
Jawaban:
Inilah teknik cepat dan kotor yang saya gunakan:
Jadi, inilah kode C #:
Dua peringatan:
LIKE "%...%"
kueri tidak diindeks.|
tag apa pun , kosong, atau nol atau ini tidak akan berfungsiAda cara lain untuk mencapai hal ini yang beberapa orang mungkin anggap lebih bersih, jadi silakan terus membaca.
sumber
Anda dapat parameter setiap nilai, jadi sesuatu seperti:
Yang akan memberi Anda:
Tidak, ini tidak terbuka untuk injeksi SQL . Satu-satunya teks yang disuntikkan ke CommandText tidak didasarkan pada input pengguna. Ini semata-mata didasarkan pada awalan "@ tag" hardcoded, dan indeks array. Indeks akan selalu berupa bilangan bulat, bukan hasil pengguna, dan aman.
Nilai yang dimasukkan pengguna masih dimasukkan ke dalam parameter, sehingga tidak ada kerentanan di sana.
Edit:
Bukan berarti paket kuota yang di-cache tidak berharga, tetapi IMO kueri ini tidak cukup rumit untuk melihat banyak manfaat darinya. Meskipun biaya kompilasi mungkin mendekati (atau bahkan melebihi) biaya eksekusi, Anda masih berbicara milidetik.
Jika Anda memiliki RAM yang cukup, saya berharap SQL Server mungkin akan men-cache rencana untuk jumlah parameter yang umum juga. Saya kira Anda selalu dapat menambahkan lima parameter, dan membiarkan tag yang tidak ditentukan menjadi NULL - rencana kueri harus sama, tetapi tampaknya cukup jelek bagi saya dan saya tidak yakin bahwa itu layak untuk optimasi mikro (walaupun, pada Stack Overflow - mungkin sangat berharga).
Selain itu, SQL Server 7 dan yang lebih baru akan auto-parameterize query , jadi menggunakan parameter tidak benar-benar diperlukan dari sudut pandang kinerja - namun, penting dari sudut pandang keamanan - terutama dengan data yang dimasukkan pengguna seperti ini.
sumber
Untuk SQL Server 2008, Anda dapat menggunakan parameter tabel bernilai . Ini sedikit bekerja, tetapi ini bisa dibilang lebih bersih daripada metode saya yang lain .
Pertama, Anda harus membuat tipe
Kemudian, kode ADO.NET Anda terlihat seperti ini:
sumber
SELECT * FROM tags WHERE tags.name IN (SELECT name from @tvp);
? Secara teori, ini seharusnya menjadi pendekatan tercepat. Anda dapat menggunakan indeks yang relevan (misalnya indeks pada nama tag yangINCLUDE
dianggap ideal), dan SQL Server harus melakukan beberapa upaya untuk mengambil semua tag dan jumlah mereka. Seperti apa rencananya?Pertanyaan aslinya adalah "Bagaimana cara parameterisasi kueri ..."
Izinkan saya menyatakan di sini, bahwa ini bukan jawaban untuk pertanyaan awal. Sudah ada beberapa demonstrasi tentang hal itu di jawaban yang baik lainnya.
Dengan mengatakan itu, silakan dan tandai jawaban ini, turunkan suaranya, tandai sebagai bukan jawaban ... lakukan apa pun yang menurut Anda benar.
Lihat jawaban dari Mark Brackett untuk jawaban yang lebih disukai yang saya (dan 231 lainnya) angkat. Pendekatan yang diberikan dalam jawabannya memungkinkan 1) untuk penggunaan variabel terikat yang efektif, dan 2) untuk predikat yang lebih besar.
Jawaban yang dipilih
Yang ingin saya sampaikan di sini adalah pendekatan yang diberikan dalam jawaban Joel Spolsky, jawaban "terpilih" sebagai jawaban yang tepat.
Pendekatan Joel Spolsky cerdas. Dan itu bekerja dengan wajar, itu akan menunjukkan perilaku yang dapat diprediksi dan kinerja yang dapat diprediksi, diberi nilai "normal", dan dengan kasus tepi normatif, seperti NULL dan string kosong. Dan itu mungkin cukup untuk aplikasi tertentu.
Tetapi dalam hal menggeneralisasikan pendekatan ini, mari kita juga mempertimbangkan kasus sudut yang lebih jelas, seperti ketika
Name
kolom berisi karakter wildcard (seperti yang dikenali oleh predikat LIKE). Karakter wildcard yang saya lihat paling umum digunakan adalah%
(tanda persen.). Jadi mari kita hadapi itu di sini sekarang, dan kemudian lanjutkan ke kasus lain.Beberapa masalah dengan% karakter
Pertimbangkan nilai Nama
'pe%ter'
. (Untuk contoh di sini, saya menggunakan nilai string literal sebagai ganti nama kolom.) Baris dengan nilai Nama `'pe% ter' akan dikembalikan oleh kueri bentuk:Tapi baris yang sama itu tidak akan dikembalikan jika urutan istilah pencarian dibalik:
Perilaku yang kita amati agak aneh. Mengubah urutan istilah pencarian dalam daftar akan mengubah set hasil.
Hampir tidak perlu dikatakan bahwa kita mungkin tidak ingin
pe%ter
mencocokkan selai kacang, tidak peduli seberapa besar dia menyukainya.Kasus sudut tidak jelas
(Ya, saya akan setuju bahwa ini adalah kasus yang tidak jelas. Mungkin yang tidak mungkin diuji. Kami tidak akan mengharapkan wildcard dalam nilai kolom. Kami dapat mengasumsikan bahwa aplikasi mencegah nilai disimpan dari nilai tersebut. Tetapi dalam pengalaman saya, saya jarang melihat kendala basis data yang secara khusus melarang karakter atau pola yang akan dianggap wildcard di sisi kanan
LIKE
operator pembanding.Menambal lubang
Salah satu pendekatan untuk menambal lubang ini adalah untuk melarikan diri dari
%
karakter wildcard. (Untuk siapa pun yang tidak terbiasa dengan klausa melarikan diri pada operator, berikut ini tautan ke dokumentasi SQL Server .Sekarang kita dapat mencocokkan% literal. Tentu saja, ketika kita memiliki nama kolom, kita harus keluar secara dinamis dari wildcard. Kita dapat menggunakan
REPLACE
fungsi untuk menemukan kemunculan%
karakter dan menyisipkan karakter garis miring terbalik di depan masing-masing karakter, seperti ini:Sehingga memecahkan masalah dengan% wildcard. Hampir.
Escape the escape
Kami menyadari bahwa solusi kami telah menimbulkan masalah lain. Karakter melarikan diri. Kita melihat bahwa kita juga perlu melarikan diri dari setiap kejadian karakter pelarian itu sendiri. Kali ini, kami menggunakan! sebagai karakter pelarian:
Garis bawah juga
Sekarang kita berada di roll, kita dapat menambahkan
REPLACE
pegangan lain wildcard garis bawah. Dan hanya untuk bersenang-senang, kali ini, kami akan menggunakan $ sebagai karakter pelarian.Saya lebih suka pendekatan ini untuk melarikan diri karena ia bekerja di Oracle dan MySQL serta SQL Server. (Saya biasanya menggunakan \ backslash sebagai karakter pelarian, karena itulah karakter yang kami gunakan dalam ekspresi reguler. Tapi mengapa harus dibatasi oleh konvensi!
Kurung sial itu
SQL Server juga memungkinkan karakter wildcard diperlakukan sebagai literal dengan melampirkannya dalam tanda kurung
[]
. Jadi kita belum selesai memperbaiki, setidaknya untuk SQL Server. Karena pasangan tanda kurung memiliki arti khusus, kita juga perlu menghindarinya. Jika kita berhasil keluar dari kurung, maka setidaknya kita tidak perlu repot dengan tanda hubung-
dan karat^
di dalam kurung. Dan kita bisa pergi%
dan_
karakter di dalam tanda kurung lolos, karena pada dasarnya kita akan menonaktifkan arti khusus tanda kurung.Menemukan pasangan kurung yang cocok seharusnya tidak sulit. Ini sedikit lebih sulit daripada menangani kejadian singleton% dan _. (Perhatikan bahwa tidak cukup untuk hanya melarikan diri dari semua kejadian kurung, karena braket tunggal dianggap literal, dan tidak perlu diloloskan. Logikanya menjadi sedikit lebih kabur daripada yang bisa saya tangani tanpa menjalankan lebih banyak kasus uji .)
Ekspresi sebaris menjadi berantakan
Ungkapan inline dalam SQL semakin panjang dan jelek. Kita mungkin dapat membuatnya bekerja, tetapi surga membantu jiwa miskin yang datang dan harus menguraikannya. Sebanyak penggemar saya untuk ekspresi inline, saya cenderung tidak menggunakannya di sini, terutama karena saya tidak ingin harus meninggalkan komentar menjelaskan alasan kekacauan, dan meminta maaf untuk itu.
Fungsi mana?
Oke, jadi, jika kita tidak mengatasinya sebagai ekspresi inline dalam SQL, alternatif terdekat yang kita miliki adalah fungsi yang ditentukan pengguna. Dan kita tahu bahwa tidak akan mempercepat apa pun (kecuali kita dapat menentukan indeks di atasnya, seperti kita bisa dengan Oracle.) Jika kita harus membuat fungsi, kita mungkin lebih baik melakukannya dalam kode yang memanggil SQL pernyataan.
Dan fungsi itu mungkin memiliki beberapa perbedaan dalam perilaku, tergantung pada DBMS dan versi. (Teriakan untuk semua pengembang Java Anda yang ingin sekali menggunakan mesin basis data secara bergantian.)
Pengetahuan domain
Kami mungkin memiliki pengetahuan khusus tentang domain untuk kolom, (yaitu, kumpulan nilai yang diizinkan yang diberlakukan untuk kolom tersebut. Kita mungkin mengetahui apriori bahwa nilai yang disimpan dalam kolom tidak akan pernah mengandung tanda persen, garis bawah, atau braket dalam hal ini, kami hanya menyertakan komentar cepat bahwa kasus-kasus tersebut dibahas.
Nilai-nilai yang disimpan dalam kolom memungkinkan% atau _ karakter, tetapi kendala mungkin mengharuskan nilai-nilai itu untuk melarikan diri, mungkin menggunakan karakter yang ditentukan, sehingga nilai-nilai tersebut SEPERTI perbandingan "aman". Sekali lagi, komentar singkat tentang set nilai yang diperbolehkan, dan khususnya karakter mana yang digunakan sebagai karakter pelarian, dan ikuti pendekatan Joel Spolsky.
Tetapi, tanpa pengetahuan khusus dan jaminan, penting bagi kami untuk setidaknya mempertimbangkan menangani kasus sudut yang tidak jelas itu, dan mempertimbangkan apakah perilaku tersebut masuk akal dan "sesuai spesifikasi".
Masalah-masalah lain direkapitulasi
Saya percaya orang lain telah cukup menunjukkan beberapa bidang lain yang dianggap umum:
Injeksi SQL (mengambil apa yang kelihatannya merupakan informasi yang disediakan pengguna, dan memasukkannya dalam teks SQL alih-alih memasoknya melalui variabel bind. Menggunakan variabel bind tidak diperlukan, itu hanya satu pendekatan yang mudah untuk menggagalkan dengan injeksi SQL. Ada yang lain cara untuk menghadapinya:
rencana pengoptimalisasi menggunakan pemindaian indeks daripada pencarian indeks, kemungkinan kebutuhan untuk ekspresi atau fungsi untuk keluar dari wildcard (indeks kemungkinan pada ekspresi atau fungsi)
menggunakan nilai literal sebagai pengganti variabel pengikat berdampak skalabilitas
Kesimpulan
Saya suka pendekatan Joel Spolsky. Itu pintar. Dan itu berhasil.
Tapi begitu saya melihatnya, saya langsung melihat potensi masalah dengan itu, dan bukan sifat saya untuk membiarkannya meluncur. Saya tidak bermaksud kritis terhadap upaya orang lain. Saya tahu banyak pengembang mengambil pekerjaan mereka dengan sangat pribadi, karena mereka berinvestasi begitu banyak ke dalamnya dan mereka sangat peduli tentang itu. Jadi tolong mengerti, ini bukan serangan pribadi. Apa yang saya identifikasi di sini adalah jenis masalah yang muncul dalam produksi daripada pengujian.
Ya, saya sudah jauh dari pertanyaan awal. Tetapi di mana lagi harus meninggalkan catatan tentang apa yang saya anggap sebagai masalah penting dengan jawaban "terpilih" untuk sebuah pertanyaan?
sumber
Anda dapat melewatkan parameter sebagai string
Jadi kamu punya talinya
Maka yang harus Anda lakukan adalah meneruskan string sebagai 1 parameter.
Berikut adalah fungsi split yang saya gunakan.
sumber
Saya mendengar Jeff / Joel membicarakan hal ini di podcast hari ini ( episode 34 , 2008-12-16 (MP3, 31 MB), 1 jam 03 menit 38 detik - 1 jam 06 menit 45 detik), dan saya pikir saya ingat Stack Overflow menggunakan LINQ ke SQL , tapi mungkin itu dibuang. Inilah hal yang sama di LINQ ke SQL.
Itu dia. Dan, ya, LINQ sudah terlihat cukup mundur, tetapi
Contains
klausa itu tampak lebih mundur bagi saya. Ketika saya harus melakukan permintaan serupa untuk sebuah proyek di tempat kerja, saya secara alami mencoba melakukan ini dengan cara yang salah dengan melakukan gabungan antara array lokal dan tabel SQL Server, dengan mencari penerjemah LINQ ke SQL akan cukup pintar untuk menangani terjemahan entah bagaimana. Itu tidak, tapi itu memberikan pesan kesalahan yang deskriptif dan mengarahkan saya ke arah menggunakan Contains .Bagaimanapun, jika Anda menjalankan ini di LINQPad yang sangat disarankan , dan menjalankan kueri ini, Anda dapat melihat SQL aktual yang dihasilkan oleh penyedia LINQ SQL. Ini akan menunjukkan kepada Anda masing-masing nilai yang mendapatkan parameter menjadi
IN
klausa.sumber
Jika Anda menelepon dari .NET, Anda bisa menggunakan Dapper dot net :
Di sini Dapper yang berpikir, jadi Anda tidak perlu melakukannya. Hal serupa mungkin terjadi dengan LINQ ke SQL , tentu saja:
sumber
Ini mungkin cara setengah jahat melakukannya, saya pernah menggunakannya, agak efektif.
Tergantung pada tujuan Anda, itu mungkin berguna.
INSERT
setiap nilai pencarian ke dalam kolom itu.IN
, Anda kemudian bisa menggunakanJOIN
aturan standar Anda . (Fleksibilitas ++)Ini memiliki sedikit fleksibilitas tambahan dalam apa yang dapat Anda lakukan, tetapi lebih cocok untuk situasi di mana Anda memiliki tabel besar untuk query, dengan pengindeksan yang baik, dan Anda ingin menggunakan daftar parametrized lebih dari sekali. Menghemat pelaksanaannya dua kali dan sanitasi dilakukan secara manual.
Saya tidak pernah sempat membuat profil seberapa cepat itu, tetapi dalam situasi saya diperlukan.
sumber
Dalam
SQL Server 2016+
Anda bisa menggunakanSTRING_SPLIT
fungsi:atau:
LiveDemo
The jawaban yang diterima tentu saja akan bekerja dan ini adalah salah satu cara untuk pergi, tapi itu adalah anti-pola.
Adendum :
Untuk meningkatkan
STRING_SPLIT
estimasi baris fungsi tabel, adalah ide yang bagus untuk mematerialisasikan nilai yang dibagi sebagai variabel tabel / tabel sementara:SEDE - Demo Langsung
Terkait: Cara Melewati Daftar Nilai Ke Prosedur yang Disimpan
Pertanyaan awal memiliki persyaratan
SQL Server 2008
. Karena pertanyaan ini sering digunakan sebagai duplikat, saya menambahkan jawaban ini sebagai referensi.sumber
Kami memiliki fungsi yang membuat variabel tabel yang dapat Anda ikuti:
Begitu:
sumber
Ini kotor, tetapi jika Anda dijamin memiliki setidaknya satu, Anda bisa melakukannya:
Memiliki IN ('tag1', 'tag2', 'tag1', 'tag1', 'tag1') akan dengan mudah dioptimalkan oleh SQL Server. Plus, Anda mendapatkan pencarian indeks langsung
sumber
Menurut pendapat saya, sumber terbaik untuk mengatasi masalah ini, adalah apa yang telah diposting di situs ini:
Syscomments. Dinakar Nethi
Menggunakan:
KREDIT UNTUK: Dinakar Nethi
sumber
Saya akan melewati parameter tipe tabel (karena ini SQL Server 2008 ), dan melakukan a
where exists
, atau inner join. Anda juga dapat menggunakan XML, menggunakansp_xml_preparedocument
, dan kemudian bahkan mengindeks tabel sementara itu.sumber
Cara yang tepat IMHO adalah menyimpan daftar dalam string karakter (panjangnya dibatasi oleh apa yang didukung DBMS); satu-satunya trik adalah bahwa (untuk menyederhanakan pemrosesan) saya memiliki pemisah (koma dalam contoh saya) di awal dan di akhir string. Idenya adalah untuk "menormalkan dengan cepat", mengubah daftar menjadi tabel satu kolom yang berisi satu baris per nilai. Ini memungkinkan Anda untuk berbalik
menjadi sebuah
atau (solusi saya mungkin lebih suka) bergabung secara teratur, jika Anda hanya menambahkan "berbeda" untuk menghindari masalah dengan nilai duplikat dalam daftar.
Sayangnya, teknik untuk mengiris string cukup spesifik untuk produk. Ini adalah versi SQL Server:
Versi Oracle:
dan versi MySQL:
(Tentu saja, "pivot" harus mengembalikan baris sebanyak jumlah item maksimum yang dapat kita temukan dalam daftar)
sumber
Jika Anda punya SQL Server 2008 atau lebih baru, saya akan menggunakan Table Valued Parameter .
Jika Anda cukup beruntung terjebak di SQL Server 2005 Anda bisa menambahkan fungsi CLR seperti ini,
Yang bisa Anda gunakan seperti ini,
sumber
Saya pikir ini adalah kasus ketika permintaan statis bukan cara untuk pergi. Secara dinamis membangun daftar untuk klausa Anda, keluar dari tanda kutip tunggal, dan secara dinamis membangun SQL. Dalam hal ini Anda mungkin tidak akan melihat banyak perbedaan dengan metode apa pun karena daftar kecil, tetapi metode yang paling efisien adalah mengirim SQL persis seperti yang tertulis dalam posting Anda. Saya pikir itu kebiasaan yang baik untuk menulisnya dengan cara yang paling efisien, daripada melakukan apa yang membuat kode tercantik, atau menganggapnya sebagai praktik buruk untuk membangun SQL secara dinamis.
Saya telah melihat fungsi split membutuhkan waktu lebih lama untuk dieksekusi daripada query sendiri dalam banyak kasus di mana parameter menjadi besar. Prosedur tersimpan dengan parameter nilai tabel di SQL 2008 adalah satu-satunya pilihan lain yang akan saya pertimbangkan, meskipun ini mungkin akan lebih lambat dalam kasus Anda. TVP mungkin hanya akan lebih cepat untuk daftar besar jika Anda mencari pada kunci utama TVP, karena SQL akan membangun tabel sementara untuk daftar itu (jika daftar besar). Anda tidak akan tahu pasti kecuali Anda mengujinya.
Saya juga melihat prosedur tersimpan yang memiliki 500 parameter dengan nilai default nol, dan memiliki WHERE Column1 IN (@ Param1, @ Param2, @ Param3, ..., @ Param500). Ini menyebabkan SQL untuk membangun tabel temp, melakukan pengurutan / berbeda, dan kemudian melakukan pemindaian tabel alih-alih pencarian indeks. Itu pada dasarnya adalah apa yang akan Anda lakukan dengan parameterisasi permintaan itu, meskipun pada skala yang cukup kecil sehingga tidak akan membuat perbedaan yang nyata. Saya sangat menyarankan agar NULL tidak ada dalam daftar IN Anda, seolah-olah itu akan berubah menjadi NOT IN itu tidak akan bertindak seperti yang dimaksudkan. Anda bisa secara dinamis membangun daftar parameter, tetapi satu-satunya hal yang jelas akan Anda dapatkan adalah bahwa objek akan lolos dari tanda kutip tunggal untuk Anda. Pendekatan itu juga sedikit lebih lambat pada ujung aplikasi karena objek harus mengurai kueri untuk menemukan parameter.
Penggunaan kembali rencana eksekusi untuk prosedur tersimpan atau kueri parameterisasi dapat memberi Anda keuntungan kinerja, tetapi itu akan mengunci Anda ke satu paket eksekusi yang ditentukan oleh kueri pertama yang dieksekusi. Itu mungkin kurang dari ideal untuk pertanyaan selanjutnya dalam banyak kasus. Dalam kasus Anda, penggunaan kembali rencana eksekusi mungkin akan menjadi nilai tambah, tetapi mungkin tidak membuat perbedaan sama sekali karena contohnya adalah permintaan yang sangat sederhana.
Catatan Cliffs:
Untuk kasus Anda, apa pun yang Anda lakukan, baik itu parameterisasi dengan jumlah item tetap dalam daftar (nol jika tidak digunakan), secara dinamis membangun kueri dengan atau tanpa parameter, atau menggunakan prosedur tersimpan dengan parameter tabel bernilai tidak akan membuat banyak perbedaan . Namun, rekomendasi umum saya adalah sebagai berikut:
Kasing / pertanyaan sederhana Anda dengan beberapa parameter:
SQL dinamis, mungkin dengan parameter jika pengujian menunjukkan kinerja yang lebih baik.
Kueri dengan rencana eksekusi yang dapat digunakan kembali, dipanggil beberapa kali hanya dengan mengubah parameter atau jika kueri rumit:
SQL dengan parameter dinamis.
Kueri dengan daftar besar:
Prosedur tersimpan dengan parameter nilai tabel. Jika daftar dapat bervariasi dengan menggunakan jumlah besar DENGAN DIREKOMENDASIKAN pada prosedur tersimpan, atau cukup gunakan SQL dinamis tanpa parameter untuk menghasilkan rencana eksekusi baru untuk setiap permintaan.
sumber
Mungkin kita bisa menggunakan XML di sini:
sumber
CTE
dan@x
dapat dihilangkan / digarisbawahi ke dalam subselect, jika dilakukan dengan sangat hati-hati, seperti yang ditunjukkan dalam artikel ini .Saya akan mendekati ini secara default dengan melewatkan fungsi bernilai tabel (yang mengembalikan tabel dari string) ke kondisi IN.
Ini adalah kode untuk UDF (saya mendapatkannya dari Stack Overflow di suatu tempat, saya tidak dapat menemukan sumbernya sekarang)
Setelah Anda mendapatkan ini, kode Anda akan sesederhana ini:
Kecuali jika Anda memiliki string yang sangat panjang, ini akan bekerja dengan baik dengan indeks tabel.
Jika perlu Anda bisa memasukkannya ke tabel temp, indekskan, kemudian jalankan gabungan ...
sumber
Solusi lain yang mungkin adalah alih-alih meneruskan sejumlah variabel argumen ke prosedur tersimpan, meneruskan string tunggal yang berisi nama-nama yang Anda cari, tetapi membuatnya unik dengan mengelilingi mereka dengan '<>'. Kemudian gunakan PATINDEX untuk menemukan nama-nama:
sumber
Gunakan prosedur tersimpan berikut ini. Ini menggunakan fungsi pemisahan kustom, yang dapat ditemukan di sini .
sumber
Jika kita memiliki string yang disimpan di dalam klausa IN dengan tanda koma (,) dibatasi, kita bisa menggunakan fungsi charindex untuk mendapatkan nilai. Jika Anda menggunakan .NET, maka Anda dapat memetakan dengan SqlParameters.
Naskah DDL:
T-SQL:
Anda dapat menggunakan pernyataan di atas dalam kode .NET Anda dan memetakan parameter dengan SqlParameter.
Demo Fiddler
EDIT: Buat tabel yang disebut SelectedTags menggunakan skrip berikut.
Naskah DDL:
T-SQL:
sumber
Untuk sejumlah variabel argumen seperti ini, satu-satunya cara yang saya ketahui adalah menghasilkan SQL secara eksplisit atau melakukan sesuatu yang melibatkan mengisi tabel sementara dengan item yang Anda inginkan dan bergabung dengan temp table.
sumber
Di ColdFusion kami hanya melakukan:
sumber
Berikut adalah teknik yang membuat ulang tabel lokal untuk digunakan dalam string kueri. Melakukannya dengan cara ini menghilangkan semua masalah parsing.
String dapat dibuat dalam bahasa apa pun. Dalam contoh ini saya menggunakan SQL karena itu adalah masalah asli yang saya coba pecahkan. Saya membutuhkan cara bersih untuk meneruskan data tabel dengan cepat dalam sebuah string untuk dieksekusi nanti.
Menggunakan tipe yang ditentukan pengguna adalah opsional. Menciptakan tipe hanya dibuat sekali dan dapat dilakukan sebelumnya. Jika tidak, tambahkan saja tipe tabel penuh ke deklarasi dalam string.
Pola umum mudah diperluas dan dapat digunakan untuk melewati tabel yang lebih kompleks.
sumber
Dalam SQL Server 2016+ kemungkinan lain adalah menggunakan
OPENJSON
fungsi.Pendekatan ini dibuat di blog tentang di OPENJSON - salah satu cara terbaik untuk memilih baris berdasarkan daftar id .
Contoh lengkap bekerja di bawah ini
sumber
Berikut ini alternatif lain. Cukup berikan daftar yang dibatasi koma sebagai parameter string ke prosedur tersimpan dan:
Dan fungsinya:
sumber
Saya punya jawaban yang tidak memerlukan UDF, XML Karena IN menerima pernyataan pilih misalnya SELECT * FROM Test mana Data IN (SELECT Value FROM TABLE)
Anda benar-benar hanya membutuhkan cara untuk mengubah string menjadi sebuah tabel.
Ini dapat dilakukan dengan CTE rekursif, atau kueri dengan tabel angka (atau Master..spt_value)
Ini versi CTE.
sumber
Saya menggunakan versi yang lebih ringkas dari jawaban terpilih :
Itu loop melalui parameter tag dua kali; tapi itu tidak masalah sebagian besar waktu (itu tidak akan menjadi hambatan Anda; jika ya, buka gulungannya).
Jika Anda benar-benar tertarik dengan kinerja dan tidak ingin mengulang melalui loop dua kali, ini versi yang kurang cantik:
sumber
Ini jawaban lain untuk masalah ini.
(versi baru diposting pada 6/4/13).
Bersulang.
sumber
Satu-satunya langkah yang menang bukanlah bermain.
Tidak ada variabilitas tak terbatas untuk Anda. Hanya variabilitas terbatas.
Dalam SQL Anda memiliki klausa seperti ini:
Dalam kode C # Anda melakukan sesuatu seperti ini:
Jadi pada dasarnya jika hitungannya 0 maka tidak ada filter dan semuanya berjalan lancar. Jika hitung lebih tinggi dari 0 maka nilainya harus ada dalam daftar, tetapi daftar telah diisi hingga lima dengan nilai yang tidak mungkin (sehingga SQL masih masuk akal)
Terkadang solusi lumpuh adalah satu-satunya yang benar-benar berfungsi.
sumber