Kebutuhan umum saat menggunakan database adalah mengakses catatan secara berurutan. Misalnya, jika saya memiliki blog, saya ingin dapat memesan ulang posting blog saya dalam urutan acak. Entri-entri ini sering memiliki banyak hubungan, jadi database relasional sepertinya masuk akal.
Solusi umum yang saya lihat adalah menambahkan kolom integer order
:
CREATE TABLE AS your_table (id, title, sort_order)
AS VALUES
(0, 'Lorem ipsum', 3),
(1, 'Dolor sit', 2),
(2, 'Amet, consect', 0),
(3, 'Elit fusce', 1);
Kemudian, kita bisa mengurutkan baris dengan order
mengatur urutannya.
Namun, ini tampak canggung:
- Jika saya ingin memindahkan record 0 ke awal, saya harus menyusun ulang setiap record
- Jika saya ingin menyisipkan catatan baru di tengah, saya harus menyusun ulang setiap catatan setelahnya
- Jika saya ingin menghapus catatan, saya harus menyusun ulang setiap catatan setelahnya
Sangat mudah untuk membayangkan situasi seperti:
- Dua catatan memiliki hal yang sama
order
- Ada celah di
order
antara catatan
Ini bisa terjadi dengan cukup mudah karena sejumlah alasan.
Ini adalah pendekatan yang diambil oleh aplikasi seperti Joomla:
Anda bisa berpendapat bahwa antarmuka di sini buruk, dan bahwa alih-alih manusia secara langsung mengedit angka, mereka harus menggunakan panah atau seret-dan-jatuhkan — dan Anda mungkin benar. Namun di balik layar, hal yang sama terjadi.
Beberapa orang telah mengusulkan menggunakan desimal untuk menyimpan pesanan, sehingga Anda dapat menggunakan "2.5" untuk menyisipkan catatan di antara catatan di urutan 2 dan 3. Dan sementara itu sedikit membantu, itu bisa dibilang lebih berantakan karena Anda bisa berakhir dengan desimal aneh (di mana Anda berhenti? 2,75? 2,875? 2,8125?)
Apakah ada cara yang lebih baik untuk menyimpan pesanan di meja?
sumber
orders
dan ddl.Jawaban:
Tidak, ada cara yang lebih sederhana.
Itu benar, kecuali jika Anda menggunakan tipe data yang mendukung nilai "antara". Jenis float dan numerik memungkinkan Anda memperbarui nilai menjadi, katakanlah, 2.5. Tetapi varchar (n) juga berfungsi. (Pikirkan 'a', 'b', 'c'; lalu pikirkan 'ba', 'bb', 'bc'.)
Tidak, ada cara yang lebih sederhana. Hapus saja barisnya. Baris yang tersisa masih akan mengurutkan dengan benar.
Kendala yang unik dapat mencegah hal itu.
Kesenjangan tidak berpengaruh pada bagaimana dbms mengurutkan nilai dalam kolom.
Anda tidak berhenti sampai Anda harus melakukannya. Dbms tidak memiliki masalah mengurutkan nilai yang memiliki 2, 7, atau 15 tempat setelah titik desimal.
Saya pikir masalah Anda yang sebenarnya adalah Anda ingin melihat nilai dalam urutan yang diurutkan sebagai bilangan bulat. Kamu bisa melakukannya.
sumber
with cte as (select *,row_number() over (order by sort_order desc) as row from test) update cte set sort_order=row;
Ini sangat sederhana. Anda perlu memiliki struktur "lubang kardinalitas":
Anda harus memiliki 2 kolom:
integer
bigint
( tidakdouble
)Sisipkan / perbarui
order = round(max_bigint / 2)
.order = round("order of first record" / 2)
order = round("max_bigint - order of last record" / 2)
4) Saat memasukkan di tengah, aturorder = round("order of record before - order of record after" / 2)
Metode ini memiliki kardinalitas yang sangat besar. Jika Anda memiliki kendala kendala atau jika Anda berpikir apa yang Anda miliki dengan kardinalitas kecil, Anda dapat membangun kembali kolom pesanan (normalisasi).
Dalam situasi maksimal dengan normalisasi (dengan struktur ini) Anda dapat memiliki "lubang kardinalitas" dalam 32 bit.
Ingatlah untuk tidak menggunakan tipe floating point - pesanan harus bernilai tepat!
sumber
Secara umum, pemesanan dilakukan sesuai dengan beberapa informasi dalam catatan, judul, ID, atau apa pun yang sesuai untuk situasi tertentu.
Jika Anda membutuhkan pemesanan khusus, menggunakan kolom bilangan bulat tidak seburuk kelihatannya. Misalnya, untuk memberi ruang bagi catatan untuk masuk ke tempat ke-5, Anda dapat melakukan sesuatu seperti:
update table_1 set place = place + 1 where place > 5
.Semoga Anda dapat mendeklarasikan kolom menjadi
unique
dan mungkin memiliki prosedur untuk membuat pengaturan ulang "atom". Rinciannya tergantung pada sistem tetapi itu adalah ide umum.sumber
Siapa peduli? Angka-angka ini hanya ada untuk ditangani oleh komputer, jadi tidak masalah berapa banyak digit fraksional yang mereka miliki atau seberapa jeleknya mereka bagi kita.
Menggunakan nilai desimal berarti bahwa untuk memindahkan item F antara item J dan K yang perlu Anda lakukan adalah memilih nilai pesanan untuk J dan K kemudian rata-rata mereka kemudian memperbarui F. Dua pernyataan SELECT dan satu pernyataan UPDATE (mungkin dilakukan menggunakan isolasi serializable untuk menghindari kebuntuan).
Jika Anda ingin melihat bilangan bulat daripada fraksi dalam output maka hitung bilangan bulat di aplikasi klien atau gunakan fungsi ROW_NUMBER () atau RANK () (jika RDBMS Anda memasukkannya).
sumber
Dalam proyek saya sendiri, saya berencana untuk mencoba solusi yang mirip dengan solusi angka desimal, tetapi menggunakan byte-array sebagai gantinya:
Idenya adalah bahwa Anda tidak akan pernah kehabisan nilai di antara yang mungkin karena dan Anda hanya menambahkan
b"\x00"
ke catatan yang terlibat jika Anda membutuhkan lebih banyak nilai. (int
tidak terikat dalam Python 3, jika tidak Anda harus memilih sepotong byte pada akhir untuk membandingkan, dengan asumsi bahwa, antara dua nilai yang berdekatan, perbedaan akan dikemas menjelang akhir.)Misalnya, Anda memiliki dua catatan,
b"\x00"
danb"\x01"
, dan Anda ingin catatan untuk pergi di antara mereka. Tidak ada nilai yang tersedia di antara0x00
dan0x01
, jadi Anda menambahkanb"\x00"
keduanya, dan sekarang Anda memiliki banyak nilai yang dapat Anda gunakan untuk menyisipkan nilai-nilai baru.Basis data dapat dengan mudah mengurutkannya karena semuanya berakhir dengan urutan leksikografis. Jika Anda menghapus catatan, itu masih dalam urutan. Dalam proyek saya, saya telah membuat
b"\x00"
danb"\xff"
sebagaiFIRST
danLAST
mencatat, untuk menggunakannya sebagai nilai virtual "dari" dan "ke" untuk menambahkan / menambahkan catatan baru:sumber
Saya menemukan jawaban ini jauh lebih baik. Mengutip sepenuhnya:
sumber