Saya sedang membangun beberapa kueri SQL di C #. Ini akan berbeda tergantung pada beberapa kondisi yang disimpan sebagai variabel dalam kode.
string Query="SELECT * FROM Table1 WHERE 1=1 ";
if (condition1)
Query += "AND Col1=0 ";
if (condition2)
Query += "AND Col2=1 ";
if (condition3)
Query += "AND Col3=2 ";
Ini berhasil, tetapi pengujian 1 = 1 tampaknya tidak elegan. Jika saya tidak menggunakannya, saya harus mengingat dan memeriksa setiap kali apakah kata kunci "di mana" sudah ditambahkan atau tidak ke kueri.
Apakah ada solusi yang lebih baik?
42 = 42
;-)Select 42
pertanyaan yang kami terima. (tidak lucu mencoba melacak sumber)If I didn't use it, I would have to remember and check every time if "where" keyword was already added or not to the query
- Itulah mengapa Anda menggunakan1 = 1
. Mesin database tetap mengoptimalkannya, jadi meskipun mungkin terlihat jelek, sejauh ini cara termudah untuk menyelesaikan masalah.Jawaban:
Simpan kondisi dalam daftar:
sumber
ToArray()
tidak diperlukan dengan .NET 4 karena ada kelebihan beban yang menerima semuaIEnumerable<string>
.Salah satu solusinya adalah dengan tidak menulis kueri secara manual dengan menambahkan string. Anda dapat menggunakan ORM, seperti Entity Framework , dan dengan LINQ ke Entitas menggunakan fitur yang ditawarkan bahasa dan framework:
sumber
PrintResults(query)
kueri yang dihasilkan kemudian akan digunakan dengan rapi sebagai kueri !!Sedikit berlebihan dalam kasus sederhana ini tetapi saya telah menggunakan kode yang mirip dengan ini di masa lalu.
Buat fungsi
Gunakan seperti ini
Dengan cara ini jika tidak ada kondisi yang ditemukan Anda bahkan tidak repot-repot memuat pernyataan where dalam kueri dan menyimpan sql server satu detik mikro untuk memproses junk where clause ketika mem-parsing pernyataan sql.
sumber
Ada solusi lain, yang mungkin juga tidak elegan, tetapi berfungsi dan menyelesaikan masalah:
Untuk:
SELECT * FROM Table1
,SELECT * FROM Table1 WHERE cond1
AND condN
sumber
WHERE
jika tidak ada predikat; 1 = 1 secara khusus ada untuk menghindari itu.String query = "SELECT * FROM Table1";
danstring jointer = " WHERE ";
?WHERE
apakahAND
s harus ditempatkan di antara kondisi?string joiner
baris denganstring joiner = " WHERE ";
, dan membiarkanjoiner = " AND ";
baris itu sendiri.Lakukan saja sesuatu seperti ini:
Ini injeksi SQL aman dan IMHO , cukup bersih. The
Remove()
hanya menghilangkan yang terakhirAND
;Ini berfungsi baik jika tidak ada kondisi yang ditetapkan, jika satu telah ditetapkan atau jika beberapa telah ditetapkan.
sumber
conditions != null
selalutrue
, seperti yang Anda inisialisasi dengan""
(kecuali di C #"" == null
). Ini mungkin harus menjadi cek, jikaconditions
tidak kosong… ;-)Tambahkan saja dua baris di belakang.
Misalnya
akan menjadi
Sementara
akan menjadi
=====================================
Terima kasih telah menunjukkan kelemahan solusi ini:
"Ini dapat merusak kueri jika, karena alasan apa pun, salah satu ketentuan berisi teks" 1 = 1 AND "atau" WHERE 1 = 1 ". Ini dapat terjadi jika ketentuan berisi subkueri atau mencoba memeriksa apakah beberapa kolom berisi teks ini, misalnya. Mungkin ini bukan masalah dalam kasus Anda, tetapi Anda harus mengingatnya… "
Untuk mengatasi masalah ini, kita perlu membedakan "main" WHERE 1 = 1 dan yang dari subkueri, yang sangat mudah:
Cukup buat "main" WHERE spesial: Saya akan menambahkan tanda "$"
Kemudian tetap tambahkan dua baris:
sumber
"1=1 AND "
atau" WHERE 1=1 "
. Ini bisa terjadi jika kondisi berisi subkueri atau mencoba memeriksa apakah beberapa kolom berisi teks ini, misalnya. Mungkin ini bukan masalah dalam kasus Anda, tetapi Anda harus mengingatnya…Gunakan ini:
sumber
QuerySub
menurut saya tidak lebih baik atau lebih buruk daripada menggunakanwhere 1=1
hack. Tetapi ini adalah kontribusi yang bijaksana.... FROM SOMETABLE WHERE
; laluTrimEnd
akan benar-benar mengurangi ini menjadi... FROM SOMETABL
. Jika ini benar-benar aStringBuilder
(yang seharusnya jika Anda memiliki banyak manipulasi string atau lebih) Anda bisa sajaQuery.Length -= "WHERE ".Length;
.Mengapa tidak menggunakan Query Builder yang sudah ada? Sesuatu seperti Kata Sql .
Ini mendukung kondisi kompleks tempat, gabungan, dan subkueri.
ini bekerja dengan Sql Server, MySql dan PostgreSql.
sumber
Solusi literal tercepat untuk apa yang Anda minta yang dapat saya pikirkan adalah ini:
Tampaknya tidak elegan, pasti, saya akan merujuk Anda ke rekomendasi CodeCaster untuk menggunakan ORM. Tetapi jika Anda berpikir tentang apa yang dilakukan di sini, Anda benar-benar tidak khawatir tentang 'membuang' 4 karakter memori, dan sangat cepat bagi komputer untuk memindahkan penunjuk 4 tempat.
Jika Anda memiliki waktu untuk mempelajari cara menggunakan ORM, itu benar-benar dapat bermanfaat bagi Anda. Tetapi sehubungan dengan ini, jika Anda mencoba untuk menjaga kondisi tambahan itu agar tidak mencapai SQL db, ini akan melakukannya untuk Anda.
sumber
Jika ini adalah SQL Server , Anda dapat membuat kode ini lebih bersih.
Ini juga mengasumsikan sejumlah parameter yang diketahui, yang mungkin merupakan asumsi yang buruk ketika saya memikirkan kemungkinannya.
Di C #, Anda akan menggunakan:
Dan kemudian di sisi SQL:
sumber
Bergantung pada kondisinya, logika boolean mungkin dapat digunakan dalam kueri. Sesuatu seperti ini :
sumber
Saya suka antarmuka stringbuilder yang lancar, jadi saya membuat beberapa ExtensionMethods.
sumber
IMHO, saya pikir pendekatan Anda salah:
Membuat kueri database dengan menggabungkan string TIDAK PERNAH merupakan ide yang baik (risiko injeksi SQL dan kode dapat dengan mudah dipatahkan jika Anda melakukan beberapa perubahan di tempat lain).
Anda dapat menggunakan ORM (Saya menggunakan NHibernate ) atau setidaknya menggunakan
SqlCommand.Parameters
Jika Anda benar-benar ingin menggunakan penggabungan string, saya akan menggunakan a
StringBuilder
(ini adalah objek yang tepat untuk penggabungan string):Sebagai pemikiran terakhir,
Where 1=1
ini benar-benar jelek tetapi SQL Server akan tetap mengoptimalkannya.sumber
SELECT * FROM Table1 WHERE AND Col1=0
tampaknya tidak benar, yang merupakan inti dariWHERE 1=1
.Dapper SqlBuilder adalah opsi yang cukup bagus. Ini bahkan digunakan dalam produksi di StackOverflow.
Baca entri blog Sam tentang itu .
Sejauh yang saya tahu, ini bukan bagian dari paket Nuget, jadi Anda harus menyalin dan menempelkan kodenya ke dalam proyek Anda atau mengunduh sumber Dapper dan membangun proyek SqlBuilder. Apa pun itu, Anda juga perlu merujuk Dapper untuk
DynamicParameters
kelas tersebut.sumber
Saya melihat ini digunakan sepanjang waktu di Oracle sambil membangun SQL dinamis dalam prosedur yang tersimpan . Saya menggunakannya dalam kueri sambil menjelajahi masalah data juga hanya untuk membuat peralihan di antara filter data yang berbeda lebih cepat ... Cukup beri komentar atau tambahkan kembali dengan mudah.
Menurut saya, ini cukup umum dan cukup mudah untuk dipahami oleh seseorang yang meninjau kode Anda.
sumber
Realisasi dengan metode penyuluhan.
sumber
Menggunakan
string
fungsi Anda juga dapat melakukannya dengan cara ini:Saya pribadi merasa mudah untuk menghapus elemen kondisional di bagian akhir, karena posisinya mudah diprediksi.
sumber
Saya memikirkan solusi yang mungkin lebih mudah dibaca:
Saya hanya tidak yakin apakah interpreter SQL juga akan mengoptimalkan
Col1 = Col1
kondisi (dicetak ketikacondition1
salah).sumber
Berikut cara yang lebih elegan:
sumber
Seperti yang telah dinyatakan, membuat SQL dengan penggabungan bukanlah ide yang bagus . Bukan hanya karena injeksi SQL. Sebagian besar karena itu jelek, sulit dirawat dan sama sekali tidak perlu . Anda harus menjalankan program Anda dengan jejak atau debug untuk melihat SQL apa yang dihasilkannya. Jika Anda menggunakan QueryFirst (disclaimer: yang saya tulis) godaan yang tidak menyenangkan akan dihapus, dan Anda bisa langsung melakukannya di SQL.
Halaman ini memiliki cakupan komprehensif tentang opsi TSQL untuk menambahkan predikat pencarian secara dinamis. Opsi berikut berguna untuk situasi di mana Anda ingin membiarkan pilihan kombinasi predikat pencarian kepada pengguna Anda.
QueryFirst memberi Anda C # null ke db NULL, jadi Anda cukup memanggil metode Execute () dengan nulls jika sesuai, dan semuanya akan berfungsi. <opinion> Mengapa C # dev sangat enggan melakukan hal-hal di SQL, meski lebih sederhana. Pikiran mengejutkan. </opinion>
sumber
Untuk langkah-langkah pemfilteran yang lebih lama, StringBuilder adalah pendekatan yang lebih baik seperti yang dikatakan banyak orang.
dalam kasus Anda, saya akan pergi dengan:
sumber
Ringkas, elegan dan manis, seperti yang ditunjukkan pada gambar di bawah ini.
sumber