Pernyataan SQL DDL (bahasa definisi data) dapat 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 hal ini. -
Saya menambahkan
serial
kolom sebagai kunci primer pengganti . Di Postgres 10 atau yang lebih baru, pertimbangkanIDENTITY
kolom sebagai gantinya. Lihat:- Mengganti nama tabel dengan aman menggunakan kolom kunci utama serial
- Kolom tabel kenaikan otomatis
- https://www.2ndquadrant.com/en/blog/postgresql-10-identity-columns/
Saya sangat merekomendasikan itu, karena nama suatu produk hampir tidak unik (bukan "kunci alami" yang bagus). Selain itu, menerapkan keunikan dan mereferensikan kolom dalam kunci asing biasanya lebih murah dengan
integer
4-byte (atau bahkanbigint
8-byte ) dibandingkan dengan string yang disimpan sebagaitext
atauvarchar
. -
Jangan gunakan nama tipe data dasar seperti
date
sebagai pengidentifikasi . Meskipun ini mungkin, ini adalah gaya yang buruk dan menyebabkan kesalahan dan pesan kesalahan yang membingungkan. Gunakan pengidentifikasi legal, huruf kecil, tanpa tanda kutip. Jangan pernah menggunakan kata-kata khusus dan hindari tanda kutip ganda jika Anda bisa. -
"nama" bukanlah nama yang baik. Saya mengganti nama kolom tabel
product
menjadiproduct
(atauproduct_name
atau serupa). Itu adalah konvensi penamaan yang lebih baik . Jika tidak, saat Anda menggabungkan beberapa tabel dalam kueri - yang Anda lakukan banyak dalam database relasional - Anda berakhir dengan beberapa kolom bernama "nama" dan harus menggunakan alias kolom untuk menyelesaikan kekacauan. Itu tidak membantu. Anti-pola lain yang tersebar luas hanya "id" sebagai nama kolom.
Saya tidak yakin apa namabill
akan menjadi.bill_id
mungkin cukup dalam kasus ini. -
price
adalah tipe datanumeric
untuk menyimpan bilangan pecahan tepat seperti yang dimasukkan (tipe presisi sewenang-wenang alih-alih tipe floating point). Jika Anda berurusan dengan bilangan bulat secara eksklusif, buatinteger
. Misalnya, Anda dapat menyimpan harga sebagai Sen . -
amount
("Products"
dalam pertanyaan Anda) masuk ke tabel tautanbill_product
dan bertipenumeric
demikian juga. Sekali lagi,integer
jika Anda berurusan dengan bilangan bulat secara eksklusif. -
Anda melihat kunci asing di
bill_product
? Saya membuat keduanya untuk mengalirkan perubahan:ON UPDATE CASCADE
. Jikaproduct_id
ataubill_id
harus berubah, perubahan tersebut mengalir ke semua entri yang bergantung dibill_product
dan tidak ada yang rusak. Itu hanya referensi tanpa makna tersendiri.
Saya juga menggunakanON DELETE CASCADE
untukbill_id
:Jika tagihan dihapus, detailnya ikut mati.
Tidak demikian untuk produk:Anda tidak ingin menghapus produk yang digunakan dalam tagihan. Postgres akan membuat kesalahan jika Anda mencoba ini. Anda akan menambahkan kolom lain keproduct
untuk menandai baris usang ("soft-delete"). -
Semua kolom dalam contoh dasar ini berakhir menjadi
NOT NULL
, jadiNULL
nilai tidak diperbolehkan. (Ya, semua kolom - kolom kunci utama didefinisikanUNIQUE NOT NULL
otomatis.) Itu karenaNULL
nilai tidak akan masuk akal di salah satu kolom. Itu membuat hidup seorang pemula lebih mudah. Tapi Anda tidak akan lolos begitu saja, Anda perlu memahamiNULL
penanganan pula. Kolom tambahan mungkin mengizinkanNULL
nilai, fungsi, dan gabungan dapat memperkenalkanNULL
nilai dalam kueri dll. -
Baca bab tentang
CREATE TABLE
dalam manual. -
Kunci utama diimplementasikan dengan indeks yang unik pada kolom kunci, yang membuat kueri dengan kondisi pada kolom PK menjadi cepat. Namun, urutan kolom kunci relevan dalam kunci multikolom. Sejak PK di
bill_product
ada di(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 untuk mencariproduct_id
yang diberikan dan tidak adabill_id
. Lihat:- Kunci utama komposit PostgreSQL
- Apakah indeks komposit juga bagus untuk kueri di bidang pertama?
- Kerja indeks di PostgreSQL
-
Baca bab tentang indeks di manual.