ฉันเชื่อว่าชื่อเรื่องนี้อธิบายได้ในตัวเอง คุณสร้างโครงสร้างตารางใน PostgreSQL เพื่อสร้างความสัมพันธ์แบบกลุ่มต่อกลุ่มได้อย่างไร
ตัวอย่างของฉัน:
Product(name, price);
Bill(name, date, Products);
ฉันเชื่อว่าชื่อเรื่องนี้อธิบายได้ในตัวเอง คุณสร้างโครงสร้างตารางใน PostgreSQL เพื่อสร้างความสัมพันธ์แบบกลุ่มต่อกลุ่มได้อย่างไร
ตัวอย่างของฉัน:
Product(name, price);
Bill(name, date, Products);
คำตอบ:
คำสั่ง SQL DDL (ภาษานิยามข้อมูล) อาจมีลักษณะดังนี้:
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
);
ฉันได้ทำการปรับเปลี่ยนเล็กน้อย:
โดยปกติความสัมพันธ์ n: mจะใช้ตารางแยกต่างหาก - bill_product
ในกรณีนี้
ฉันเพิ่มserial
คอลัมน์เป็นคีย์หลักตัวแทน ใน Postgres 10 หรือใหม่กว่าให้พิจารณาIDENTITY
คอลัมน์แทน ดู:
ฉันขอแนะนำเป็นอย่างยิ่งเนื่องจากชื่อของผลิตภัณฑ์แทบจะไม่ซ้ำกันเลย (ไม่ใช่ "คีย์ธรรมชาติ" ที่ดี) นอกจากนี้การบังคับใช้เอกลักษณ์และอ้างอิงในคอลัมน์คีย์ต่างประเทศโดยทั่วไปจะมีราคาถูกกว่ากับ 4 ไบต์integer
(หรือแม้กระทั่ง 8 ไบต์bigint
) กว่าด้วยสตริงเก็บไว้เป็นหรือtext
varchar
อย่าใช้ชื่อของชนิดข้อมูลพื้นฐานเช่นdate
เป็นตัวบ่งชี้ แม้ว่าจะเป็นไปได้ แต่ก็เป็นรูปแบบที่ไม่ดีและนำไปสู่ข้อผิดพลาดและข้อความแสดงข้อผิดพลาดที่สับสน ใช้กฎหมายกรณีที่ต่ำกว่าตัวระบุ unquoted อย่าใช้คำสงวนและหลีกเลี่ยงการใช้ตัวระบุกรณีแบบผสมที่ยกมาสองคำหากทำได้
"ชื่อ" ไม่ใช่ชื่อที่ดี ฉันเปลี่ยนชื่อคอลัมน์ของตารางproduct
เป็นproduct
( product_name
หรือคล้ายกัน) นั่นคือการที่ดีกว่าการตั้งชื่อ มิฉะนั้นเมื่อคุณเข้าร่วมสองสามตารางในแบบสอบถามซึ่งคุณทำจำนวนมากในฐานข้อมูลเชิงสัมพันธ์คุณจะได้คอลัมน์หลายคอลัมน์ชื่อ "ชื่อ" และต้องใช้นามแฝงคอลัมน์เพื่อจัดระเบียบ นั่นไม่เป็นประโยชน์ รูปแบบการต่อต้านที่แพร่หลายอีกรูปแบบหนึ่งจะเป็นเพียง "id" เป็นชื่อคอลัมน์
ฉันไม่แน่ใจว่าชื่อของ a bill
จะเป็นอย่างไร bill_id
อาจจะพอเพียงในกรณีนี้
price
เป็นประเภทข้อมูล numeric
เพื่อจัดเก็บตัวเลขเศษส่วนอย่างแม่นยำตามที่ป้อน (ประเภทความแม่นยำโดยพลการแทนประเภทจุดลอยตัว) หากคุณจัดการกับจำนวนเต็มโดยเฉพาะให้ทำinteger
เช่นนั้น ตัวอย่างเช่นคุณสามารถบันทึกราคาเป็นเซ็นต์
amount
("Products"
ในคำถามของคุณ) ไปลงในตารางการเชื่อมโยงbill_product
และเป็นประเภทnumeric
ได้เป็นอย่างดี อีกครั้งinteger
หากคุณจัดการกับจำนวนเต็มโดยเฉพาะ
คุณเห็นคีย์ต่างประเทศในbill_product
? ฉันสร้างทั้งสองเพื่อเรียงซ้อนการเปลี่ยนแปลง: ON UPDATE CASCADE
. หาก a product_id
หรือbill_id
ควรเปลี่ยนการเปลี่ยนแปลงจะเรียงซ้อนกันไปยังรายการทั้งหมดโดยbill_product
ไม่มีอะไรหยุดพัก สิ่งเหล่านี้เป็นเพียงการอ้างอิงโดยไม่มีความสำคัญของตัวเอง
ฉันยังใช้ON DELETE CASCADE
สำหรับbill_id
: หากใบเรียกเก็บเงินถูกลบรายละเอียดจะตายไปด้วย
ไม่ใช่สำหรับผลิตภัณฑ์: คุณไม่ต้องการลบผลิตภัณฑ์ที่ใช้ในใบเรียกเก็บเงิน Postgres จะแสดงข้อผิดพลาดหากคุณพยายามทำเช่นนี้ คุณจะต้องเพิ่มคอลัมน์อื่นproduct
เพื่อทำเครื่องหมายแถวที่ล้าสมัย ("soft-delete") แทน
คอลัมน์ทั้งหมดในขั้นพื้นฐานเช่นปลายขึ้นเพื่อเป็นNOT NULL
ดังนั้นNULL
ค่าไม่ได้รับอนุญาต (ใช่คอลัมน์ทั้งหมด - คอลัมน์คีย์หลักถูกกำหนดUNIQUE NOT NULL
โดยอัตโนมัติ) นั่นเป็นเพราะNULL
ค่าต่างๆไม่สมเหตุสมผลในคอลัมน์ใด ๆ ทำให้ชีวิตของผู้เริ่มต้นง่ายขึ้น แต่คุณจะไม่หนีไปง่ายๆคุณต้องเข้าใจNULL
การจัดการอยู่ดี คอลัมน์เพิ่มเติมอาจอนุญาตให้NULL
ค่าฟังก์ชันและการรวมสามารถแนะนำNULL
ค่าในแบบสอบถามเป็นต้น
อ่านบทที่ CREATE TABLE
ในคู่มือ
คีย์หลักถูกนำไปใช้กับดัชนีที่ไม่ซ้ำกันในคอลัมน์คีย์ซึ่งจะทำให้การสืบค้นมีเงื่อนไขในคอลัมน์ PK ทำได้อย่างรวดเร็ว อย่างไรก็ตามลำดับของคอลัมน์หลักมีความเกี่ยวข้องในคีย์หลายคอลัมน์ เนื่องจาก PK เปิดbill_product
อยู่(bill_id, product_id)
ในตัวอย่างของฉันคุณอาจต้องการเพิ่มดัชนีอื่นในเพียงproduct_id
หรือ(product_id, bill_id)
หากคุณมีข้อสงสัยมองหาที่กำหนดและไม่มีการproduct_id
bill_id
ดู:
bill_product
อย่างไร โดยปกติควรมีลักษณะดังนี้: CREATE INDEX idx_bill_product_id ON booked_rates(bill_id, product_id)
. นี่ใช่มั้ย?
bill
แถวสำหรับแต่ละการเรียกเก็บเงินในตาราง เราต้องการจำนวนต่อรายการที่เพิ่มเข้าbill_product
มา