Saya yakin judulnya sudah cukup jelas. Bagaimana Anda membuat struktur tabel di PostgreSQL untuk membuat hubungan banyak-ke-banyak.
Contoh saya:
Product(name, price);
Bill(name, date, Products);
sql
database
postgresql
database-design
many-to-many
Radu Gheorghiu
sumber
sumber
Jawaban:
Pernyataan SQL DDL (bahasa definisi data) akan terlihat seperti ini:
CREATE TABLE product ( product_id serial PRIMARY KEY -- implicit primary key constraint , product text NOT NULL , price numeric NOT NULL DEFAULT 0 ); CREATE TABLE bill ( bill_id serial PRIMARY KEY , bill text NOT NULL , billdate date NOT NULL DEFAULT CURRENT_DATE ); CREATE TABLE bill_product ( bill_id int REFERENCES bill (bill_id) ON UPDATE CASCADE ON DELETE CASCADE , product_id int REFERENCES product (product_id) ON UPDATE CASCADE , amount numeric NOT NULL DEFAULT 1 , CONSTRAINT bill_product_pkey PRIMARY KEY (bill_id, product_id) -- explicit pk );
Saya membuat beberapa penyesuaian:
Hubungan n: m biasanya diimplementasikan oleh tabel terpisah -
bill_product
dalam kasus ini.Saya menambahkan
serial
kolom sebagai kunci utama pengganti . Di Postgres 10 atau yang lebih baru, pertimbangkanIDENTITY
kolom sebagai gantinya. Lihat:Saya sangat merekomendasikannya, karena nama suatu produk hampir tidak unik (bukan "kunci alami" yang baik). Juga, menegakkan keunikan dan mereferensikan kolom dalam kunci asing biasanya lebih murah dengan 4-byte
integer
(atau bahkan 8-bytebigint
) dibandingkan dengan string yang disimpan sebagaitext
atauvarchar
.Jangan gunakan nama tipe data dasar seperti
date
sebagai pengenal . Meskipun ini mungkin, itu adalah gaya yang buruk dan menyebabkan kesalahan yang membingungkan dan pesan kesalahan. Gunakan tanda kutip legal, huruf kecil, dan tidak dikutip . Jangan pernah menggunakan kata - kata khusus dan hindari pengenal huruf campuran yang dikutip ganda jika Anda bisa."nama" bukanlah nama yang baik. Saya mengganti nama kolom tabel
product
menjadiproduct
(product_name
atau serupa). Itu adalah konvensi penamaan yang lebih baik . Jika tidak, ketika Anda bergabung beberapa tabel dalam query - yang Anda lakukan banyak dalam database relasional - Anda berakhir dengan beberapa kolom bernama "nama" dan harus menggunakan alias kolom memilah kekacauan. Itu tidak membantu. Anti-pola lain yang tersebar luas hanya akan menjadi "id" sebagai nama kolom.Saya tidak yakin
bill
akan menjadi apa nama itu.bill_id
mungkin akan cukup dalam kasus ini.price
adalah tipe datanumeric
untuk menyimpan bilangan pecahan persis seperti yang dimasukkan (tipe presisi arbitrer, bukan tipe floating point). Jika Anda berurusan dengan bilangan bulat secara eksklusif, buat ituinteger
. Misalnya, Anda bisa menghemat harga sebagai Cents .The
amount
("Products"
dalam pertanyaan Anda) masuk ke tabel penghubungbill_product
dan juga bertipenumeric
. Sekali lagi,integer
jika Anda berurusan dengan bilangan bulat secara eksklusif.Anda melihat kunci asing masuk
bill_product
? Saya membuat keduanya untuk perubahan cascade:ON UPDATE CASCADE
. Jika aproduct_id
ataubill_id
harus berubah, perubahan tersebut mengalir ke semua entri yang bergantungbill_product
dan tidak ada yang rusak. Itu hanya referensi tanpa arti penting mereka sendiri.Saya juga digunakan
ON DELETE CASCADE
untukbill_id
: Jika sebuah tagihan dihapus, detailnya ikut mati.Tidak demikian halnya untuk produk: Anda tidak ingin menghapus produk yang digunakan dalam tagihan. Postgres akan memberikan kesalahan jika Anda mencoba ini. Anda akan menambahkan kolom lain ke
product
untuk menandai baris usang ("hapus lunak") sebagai gantinya.Semua kolom dalam contoh dasar ini berakhir menjadi
NOT NULL
, jadiNULL
nilai tidak diperbolehkan. (Ya, semua kolom - kolom kunci utama ditentukanUNIQUE NOT NULL
secara otomatis.) Itu karenaNULL
nilai tidak masuk akal di kolom mana pun. Itu membuat hidup seorang pemula lebih mudah. Tetapi Anda tidak akan lolos begitu saja, Anda harus memahamiNULL
penanganannya . Kolom tambahan mungkin memungkinkanNULL
nilai, fungsi dan gabungan dapat memperkenalkanNULL
nilai dalam kueri, dll.Baca bab
CREATE TABLE
di manual .Kunci utama diimplementasikan dengan indeks unik pada kolom kunci, yang membuat kueri dengan kondisi pada kolom PK menjadi cepat. Namun, urutan kolom kunci relevan dalam kunci multikolom. Karena PK pada
bill_product
pada(bill_id, product_id)
dalam contoh saya, Anda mungkin ingin menambahkan indeks lain hanya padaproduct_id
atau(product_id, bill_id)
jika Anda memiliki pertanyaan mencari diberikanproduct_id
dan tidak adabill_id
. Lihat:Baca bab tentang indeks di manual .
sumber
bill_product
? Biasanya itu harus terlihat seperti:CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. Apakah ini benar?bill
. Kami membutuhkan jumlah per item yang ditambahkanbill_product
.