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_productdalam hal ini. -
Saya menambahkan
serialkolom sebagai kunci primer pengganti . Di Postgres 10 atau yang lebih baru, pertimbangkanIDENTITYkolom 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
integer4-byte (atau bahkanbigint8-byte ) dibandingkan dengan string yang disimpan sebagaitextatauvarchar. -
Jangan gunakan nama tipe data dasar seperti
datesebagai 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
productmenjadiproduct(atauproduct_nameatau 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 namabillakan menjadi.bill_idmungkin cukup dalam kasus ini. -
priceadalah tipe datanumericuntuk 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_productdan bertipenumericdemikian juga. Sekali lagi,integerjika Anda berurusan dengan bilangan bulat secara eksklusif. -
Anda melihat kunci asing di
bill_product? Saya membuat keduanya untuk mengalirkan perubahan:ON UPDATE CASCADE. Jikaproduct_idataubill_idharus berubah, perubahan tersebut mengalir ke semua entri yang bergantung dibill_productdan tidak ada yang rusak. Itu hanya referensi tanpa makna tersendiri.
Saya juga menggunakanON DELETE CASCADEuntukbill_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 keproductuntuk menandai baris usang ("soft-delete"). -
Semua kolom dalam contoh dasar ini berakhir menjadi
NOT NULL, jadiNULLnilai tidak diperbolehkan. (Ya, semua kolom - kolom kunci utama didefinisikanUNIQUE NOT NULLotomatis.) Itu karenaNULLnilai tidak akan masuk akal di salah satu kolom. Itu membuat hidup seorang pemula lebih mudah. Tapi Anda tidak akan lolos begitu saja, Anda perlu memahamiNULLpenanganan pula. Kolom tambahan mungkin mengizinkanNULLnilai, fungsi, dan gabungan dapat memperkenalkanNULLnilai dalam kueri dll. -
Baca bab tentang
CREATE TABLEdalam 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_productada di(bill_id, product_id)dalam contoh saya, Anda mungkin ingin menambahkan indeks lain hanya padaproduct_idatau(product_id, bill_id)jika Anda memiliki pertanyaan untuk mencariproduct_idyang 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.