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);
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);
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, pertimbangkan IDENTITY
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-byte bigint
) dibandingkan dengan string yang disimpan sebagai text
atau varchar
.
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
menjadi product
( 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 data numeric
untuk menyimpan bilangan pecahan persis seperti yang dimasukkan (tipe presisi arbitrer, bukan tipe floating point). Jika Anda berurusan dengan bilangan bulat secara eksklusif, buat itu integer
. Misalnya, Anda bisa menghemat harga sebagai Cents .
The amount
( "Products"
dalam pertanyaan Anda) masuk ke tabel penghubung bill_product
dan juga bertipe numeric
. 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 a product_id
atau bill_id
harus berubah, perubahan tersebut mengalir ke semua entri yang bergantung bill_product
dan tidak ada yang rusak. Itu hanya referensi tanpa arti penting mereka sendiri.
Saya juga digunakan ON DELETE CASCADE
untuk bill_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
, jadi NULL
nilai tidak diperbolehkan. (Ya, semua kolom - kolom kunci utama ditentukan UNIQUE NOT NULL
secara otomatis.) Itu karena NULL
nilai tidak masuk akal di kolom mana pun. Itu membuat hidup seorang pemula lebih mudah. Tetapi Anda tidak akan lolos begitu saja, Anda harus memahami NULL
penanganannya . Kolom tambahan mungkin memungkinkan NULL
nilai, fungsi dan gabungan dapat memperkenalkan NULL
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 pada product_id
atau (product_id, bill_id)
jika Anda memiliki pertanyaan mencari diberikan product_id
dan tidak ada bill_id
. Lihat:
Baca bab tentang indeks di manual .
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 ditambahkan bill_product
.