Anda memerlukan tautan N:M di antara books
dan authors
, karena sebuah buku mungkin memiliki beberapa penulis dan setiap penulis mungkin telah menulis lebih dari satu buku. Dalam RDBMS itu berarti Anda memerlukan written_by
tabel.
Tautan antara books
dan publishers
namun berbeda. Buku apa pun hanya dapat memiliki satu penerbit (kecuali di sistem Anda, edisi buku yang berbeda dianggap sebagai buku yang sama). Jadi yang Anda butuhkan di sini adalah publisher_id
kunci asing di books
Terakhir, dan yang paling penting Anda melihat pembaca/pengguna. Dan hubungannya dengan buku. Secara alami, ini juga merupakan relasi N:M. Saya sangat berharap bahwa orang membaca lebih dari satu buku (kita semua tahu apa yang terjadi jika Anda hanya membaca satu...) dan tentunya sebuah buku dibaca oleh lebih dari satu orang. Itu membutuhkan book_users
meja koneksi. Pertanyaan sebenarnya di sini adalah, bagaimana merancangnya. Ada tiga desain dasar.
-
Pisahkan tabel menurut jenis relasi . (seperti yang digariskan oleh @just_somebody ) Keuntungan:Anda hanya memiliki INSERTS dan DELETES, tidak pernah UPDATES. Meskipun ini terlihat rapi, dan agak membantu pengoptimalan kueri, sebagian besar waktu ini tidak memiliki tujuan sebenarnya selain memamerkan bagan basis data yang besar.
-
Satu tabel dengan
status
indikator . (seperti yang digariskan oleh @Hardcoded) Keuntungan:Anda hanya memiliki satu tabel. Kekurangan:Anda akan memiliki INSERTS, UPDATES, dan DELETES - sesuatu yang dapat dengan mudah ditangani oleh RDBMS, tetapi memiliki kekurangan karena berbagai alasan (lebih lanjut tentang itu nanti) Juga, satustatus
bidang menyiratkan bahwa satu pembaca hanya dapat memiliki satu koneksi ke buku setiap saat, artinya dia hanya bisa berada diplan_to_read
,is_reading
atauhas_read
status pada setiap titik waktu, dan mengasumsikan urutan waktu ini terjadi. Jika orang itu berencana untuk membacanya lagi , atau jeda, lalu baca ulang dari awal dll, rangkaian indikator status yang begitu sederhana dapat dengan mudah gagal, karena tiba-tiba orang tersebutis_reading
sekarang, tetapi jugahas_read
hal. Untuk sebagian besar aplikasi, ini masih merupakan pendekatan yang masuk akal, dan biasanya ada cara untuk mendesain bidang status sehingga keduanya saling eksklusif. -
Sebuah log . Anda MASUKKAN setiap status sebagai baris baru dalam tabel - kombinasi buku dan pembaca yang sama akan muncul lebih dari sekali. Anda INSERT baris pertama dengan
plan_to_read
, dan stempel waktu. Satu lagi denganis_reading
. Kemudian satu lagi denganhas_read
. Keuntungan:Anda hanya perlu INSERT baris, dan Anda mendapatkan kronologi yang rapi dari hal-hal yang terjadi. Kekurangan:Penggabungan tabel silang sekarang harus menangani lebih banyak data (dan lebih kompleks) daripada pendekatan yang lebih sederhana di atas.
Anda mungkin bertanya pada diri sendiri, mengapa ada penekanan pada apakah Anda INSERT, UPDATE atau DELETE dalam skenario apa? Singkatnya, setiap kali Anda menjalankan pernyataan UPDATE atau DELETE, kemungkinan besar Anda sebenarnya kalah data. Pada saat itu Anda perlu berhenti dalam proses desain Anda dan berpikir "Apa yang saya hilangkan di sini?" Dalam hal ini, Anda kehilangan urutan kronologis peristiwa. Jika apa yang dilakukan pengguna dengan buku mereka adalah pusat dari aplikasi Anda, Anda mungkin ingin mengumpulkan data sebanyak mungkin. Bahkan jika itu tidak penting sekarang, itu adalah jenis data yang memungkinkan Anda untuk melakukan "keajaiban" di kemudian hari. Anda dapat mengetahui seberapa cepat seseorang membaca, berapa banyak upaya yang mereka butuhkan untuk menyelesaikan sebuah buku, dll. Semua itu tanpa meminta masukan tambahan dari pengguna.
Jadi, jawaban terakhir saya sebenarnya adalah sebuah pertanyaan:
Sunting
Karena mungkin tidak jelas seperti apa log itu, dan bagaimana fungsinya, berikut adalah contoh tabelnya:
CREATE TABLE users_reading_log (
user_id INT,
book_id INT,
status ENUM('plans_to_read', 'is_reading', 'has_read'),
ts TIMESTAMP DEFAULT NOW()
)
Sekarang, alih-alih memperbarui tabel "user_read" dalam skema yang Anda rancang setiap kali status buku berubah, Anda sekarang MASUKKAN data yang sama di log yang sekarang diisi dengan kronologi informasi:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='plans_to_read';
Ketika orang itu benar-benar mulai membaca, Anda melakukan penyisipan lagi:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='is_reading';
dan seterusnya. Sekarang Anda memiliki database "peristiwa" dan karena kolom stempel waktu secara otomatis terisi sendiri, Anda sekarang dapat mengetahui apa yang terjadi kapan. Harap perhatikan bahwa sistem ini tidak memastikan bahwa hanya ada satu 'is_reading' untuk pasangan buku pengguna tertentu. Seseorang mungkin berhenti membaca dan kemudian melanjutkan. Gabung Anda harus memperhitungkan itu.