Ini adalah masalah yang saya habiskan berjam-jam meneliti di masa lalu. Tampaknya bagi saya adalah sesuatu yang seharusnya ditangani oleh solusi RDBMS modern tetapi sampai sekarang saya belum menemukan apa pun yang benar-benar menjawab apa yang saya lihat sebagai kebutuhan yang sangat umum dalam aplikasi Web atau Windows dengan basis data back-end.
Saya berbicara tentang penyortiran dinamis. Di dunia fantasi saya, itu harus sesederhana sesuatu seperti:
ORDER BY @sortCol1, @sortCol2
Ini adalah contoh kanonik yang diberikan oleh pengembang SQL dan Stored Procedure pemula di seluruh forum di Internet. "Mengapa ini tidak mungkin?" mereka bertanya. Selalu, seseorang akhirnya datang untuk memberi tahu mereka tentang sifat kompilasi dari prosedur tersimpan, rencana eksekusi secara umum, dan segala macam alasan lain mengapa tidak mungkin untuk menempatkan parameter secara langsung ke dalam ORDER BY
klausa.
Saya tahu apa yang sudah Anda pikirkan: "Biarkan klien melakukan penyortiran, kalau begitu." Secara alami, ini membongkar pekerjaan dari basis data Anda. Dalam kasus kami, server database kami bahkan tidak berkeringat 99% dari waktu dan mereka bahkan belum multi-core atau salah satu dari banyak sekali peningkatan lainnya untuk arsitektur sistem yang terjadi setiap 6 bulan. Untuk alasan ini saja, memiliki database kami menangani penyortiran tidak akan menjadi masalah. Selain itu, basis data sangatpandai menyortir. Mereka dioptimalkan untuk itu dan telah bertahun-tahun untuk melakukannya dengan benar, bahasa untuk melakukannya sangat fleksibel, intuitif, dan sederhana dan di atas semua penulis SQL pemula tahu bagaimana melakukannya dan bahkan lebih penting lagi mereka tahu cara mengeditnya, membuat perubahan, melakukan pemeliharaan, dll. Ketika database Anda jauh dari pajak dan Anda hanya ingin menyederhanakan (dan mempersingkat!) waktu pengembangan ini sepertinya pilihan yang jelas.
Lalu ada masalah web. Saya telah bermain-main dengan JavaScript yang akan melakukan pemilahan tabel HTML sisi klien, tetapi mereka pasti tidak cukup fleksibel untuk kebutuhan saya dan, sekali lagi, karena basis data saya tidak dikenai pajak dan dapat melakukan pengurutan dengan sangat mudah, saya mengalami kesulitan membenarkan waktu yang diperlukan untuk menulis ulang atau menyortir penyortir JavaScript saya sendiri. Hal yang sama berlaku untuk penyortiran sisi server, meskipun mungkin sudah lebih disukai daripada JavaScript. Saya bukan orang yang suka overhead DataSets, jadi tuntut saya.
Tetapi ini membawa kembali poin bahwa itu tidak mungkin - atau lebih tepatnya, tidak mudah. Saya telah melakukan, dengan sistem sebelumnya, cara hack yang luar biasa untuk mendapatkan penyortiran dinamis. Itu tidak cantik, tidak intuitif, sederhana, atau fleksibel dan penulis SQL pemula akan hilang dalam hitungan detik. Sudah mencari bukan "solusi" tapi "komplikasi."
Contoh-contoh berikut ini tidak dimaksudkan untuk mengekspos segala praktik terbaik atau gaya pengkodean yang baik atau apa pun, juga tidak menunjukkan kemampuan saya sebagai programmer T-SQL. Mereka adalah apa adanya dan saya sepenuhnya mengakui mereka membingungkan, bentuk buruk, dan sekadar peretasan.
Kami meneruskan nilai integer sebagai parameter ke prosedur tersimpan (sebut saja parameter "sort") dan dari situ kami menentukan banyak variabel lain. Misalnya ... katakanlah sort adalah 1 (atau default):
DECLARE @sortCol1 AS varchar(20)
DECLARE @sortCol2 AS varchar(20)
DECLARE @dir1 AS varchar(20)
DECLARE @dir2 AS varchar(20)
DECLARE @col1 AS varchar(20)
DECLARE @col2 AS varchar(20)
SET @col1 = 'storagedatetime';
SET @col2 = 'vehicleid';
IF @sort = 1 -- Default sort.
BEGIN
SET @sortCol1 = @col1;
SET @dir1 = 'asc';
SET @sortCol2 = @col2;
SET @dir2 = 'asc';
END
ELSE IF @sort = 2 -- Reversed order default sort.
BEGIN
SET @sortCol1 = @col1;
SET @dir1 = 'desc';
SET @sortCol2 = @col2;
SET @dir2 = 'desc';
END
Anda sudah dapat melihat bagaimana jika saya mendeklarasikan lebih banyak variabel @colX untuk mendefinisikan kolom lain, saya benar-benar bisa berkreasi dengan kolom untuk mengurutkan berdasarkan nilai "sort" ... untuk menggunakannya, biasanya berakhir seperti berikut ini. klausa yang sangat berantakan:
ORDER BY
CASE @dir1
WHEN 'desc' THEN
CASE @sortCol1
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END DESC,
CASE @dir1
WHEN 'asc' THEN
CASE @sortCol1
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END,
CASE @dir2
WHEN 'desc' THEN
CASE @sortCol2
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END DESC,
CASE @dir2
WHEN 'asc' THEN
CASE @sortCol2
WHEN @col1 THEN [storagedatetime]
WHEN @col2 THEN [vehicleid]
END
END
Jelas ini adalah contoh yang sangat sederhana. Hal-hal nyata, karena kami biasanya memiliki empat atau lima kolom untuk mendukung penyortiran, masing-masing dengan kemungkinan kolom kedua atau bahkan ketiga untuk disortir di samping itu (misalnya tanggal turun lalu disortir secara sekunder dengan nama naik) dan masing-masing mendukung dua pengurutan terarah yang secara efektif menggandakan jumlah kasus. Ya ... rambut itu menjadi sangat cepat.
Idenya adalah bahwa seseorang dapat "dengan mudah" mengubah kasus semacam itu sehingga vehicleid bisa disortir sebelum masa penyimpanan ... tetapi fleksibilitas semu, setidaknya dalam contoh sederhana ini, benar-benar berakhir di sana. Pada dasarnya, setiap kasus yang gagal tes (karena metode pengurutan kami tidak berlaku untuk kali ini) memberikan nilai NULL. Dan akhirnya Anda memiliki klausa yang berfungsi seperti berikut:
ORDER BY NULL DESC, NULL, [storagedatetime] DESC, blah blah
Anda mendapatkan idenya. Ini berfungsi karena SQL Server secara efektif mengabaikan nilai null dalam urutan klausa. Ini sangat sulit untuk dipertahankan, karena siapa pun yang memiliki pengetahuan dasar SQL mungkin bisa melihatnya. Jika saya kehilangan salah satu dari Anda, jangan merasa buruk. Kami butuh waktu lama untuk membuatnya berfungsi dan kami masih bingung mencoba mengeditnya atau membuat yang baru seperti itu. Untungnya itu tidak perlu sering berubah, kalau tidak cepat akan menjadi "tidak sepadan dengan masalah."
Namun melakukan pekerjaan.
Pertanyaan saya kemudian: apakah ada cara yang lebih baik?
Saya baik-baik saja dengan solusi selain yang Disimpan Prosedur, karena saya menyadari itu mungkin bukan jalan untuk pergi. Lebih disukai, saya ingin tahu apakah ada yang bisa melakukannya dengan lebih baik dalam Prosedur Tersimpan, tetapi jika tidak, bagaimana Anda semua menangani membiarkan pengguna secara dinamis mengurutkan tabel data (dua arah juga) dengan ASP.NET?
Dan terima kasih telah membaca (atau setidaknya membaca sepintas lalu) pertanyaan panjang!
PS: Senang saya tidak menunjukkan contoh saya tentang prosedur tersimpan yang mendukung penyortiran dinamis, penyaringan dinamis / pencarian teks kolom, pagination melalui ROWNUMBER () LEBIH, DAN coba ... tangkap dengan transaksi rollbacking pada kesalahan ... "ukuran raksasa" bahkan tidak mulai menggambarkannya.
Memperbarui:
- Saya ingin menghindari SQL dinamis . Parsing string bersama-sama dan menjalankan EXEC di atasnya mengalahkan banyak tujuan memiliki prosedur tersimpan di tempat pertama. Kadang-kadang saya bertanya-tanya apakah jika melakukan hal seperti itu tidak akan sepadan, setidaknya dalam kasus penyortiran dinamis khusus ini. Namun, saya selalu merasa kotor setiap kali saya melakukan string SQL dinamis seperti itu - seperti saya masih hidup di dunia ASP Klasik.
- Banyak alasan kami ingin prosedur tersimpan di tempat pertama adalah untuk keamanan . Saya tidak bisa membuat panggilan pada masalah keamanan, hanya menyarankan solusi. Dengan SQL Server 2005 kita dapat mengatur izin (berdasarkan per pengguna jika perlu) di tingkat skema pada masing-masing prosedur yang tersimpan dan kemudian menolak setiap pertanyaan terhadap tabel secara langsung. Mengkritik pro dan kontra dari pendekatan ini mungkin untuk pertanyaan lain, tetapi sekali lagi itu bukan keputusan saya. Saya hanya monyet kode utama. :)