ฉันเชื่อว่าชื่อเรื่องนี้อธิบายได้ในตัวเอง คุณสร้างโครงสร้างตารางใน 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) กว่าด้วยสตริงเก็บไว้เป็นหรือtextvarchar
อย่าใช้ชื่อของชนิดข้อมูลพื้นฐานเช่น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มา