2012-03-20 41 views
35

Tôi tin rằng tiêu đề là tự giải thích. Làm thế nào để bạn tạo cấu trúc bảng trong PostgreSQL để tạo mối quan hệ nhiều-nhiều.Làm thế nào để thực hiện mối quan hệ nhiều-nhiều trong PostgreSQL?

dụ của tôi:

Product(name, price); 
Bill(name, date, Products); 
+1

Truy vấn không thiết lập mối quan hệ m-t-m - cấu trúc bảng làm. –

+0

Tôi không thể hiện bản thân mình tốt, làm cách nào để xác định cấu trúc bảng của mình? –

+1

xóa sản phẩm khỏi bảng hóa đơn, tạo bảng mới có tên là "bill_products" với hai trường: một trỏ vào sản phẩm, một trỏ vào hóa đơn. làm cho hai trường này trở thành khóa chính của bảng mới này. –

Trả lời

164

Các lệnh DDL có thể trông như thế này:

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 
); 

tôi đã thực hiện một vài điều chỉnh:

  • Các n: mối quan hệ m là thường được thực hiện bởi một bảng riêng biệt - bill_product trong th là trường hợp.

  • Tôi đã thêm serial các cột là khóa chính thay thế. Tôi rất khuyên bạn nên, bởi vì tên của một sản phẩm hầu như không phải là duy nhất. Ngoài ra, việc thực thi tính duy nhất và tham chiếu cột trong khóa ngoài rẻ hơn nhiều với một byte integer 4 byte so với chuỗi được lưu trữ là text hoặc varchar.
    Trong Postgres 10 hoặc mới hơn, hãy xem xét một số IDENTITY column thay thế. Thông tin chi tiết:

  • Không sử dụng tên của kiểu dữ liệu cơ bản như date như định danh. Trong khi điều này là có thể, nó là phong cách xấu và dẫn đến các lỗi khó hiểu và thông báo lỗi. Sử dụng legal, lower case, unquoted identifiers. Không bao giờ sử dụng reserved words và tránh nhận dạng chữ hoa kép hỗn hợp nếu bạn có thể.

  • name không phải là tên tốt. Tôi đã đổi tên cột name của bảng product thành product. Đó là quy ước đặt tên tốt hơn. Nếu không, khi bạn tham gia một vài bảng trong truy vấn - bạn thực hiện rất nhiều trong cơ sở dữ liệu quan hệ - bạn kết thúc với nhiều cột có tên name và phải sử dụng bí danh cột để phân loại mớ hỗn độn. Điều đó không hữu ích. Một mẫu chống phổ biến khác sẽ chỉ là id làm tên cột.
    Tôi không chắc chắn tên của bill sẽ là gì. Có thể bill_id có thể là tên trong trường hợp này.

  • price là loại dữ liệunumeric để lưu trữ số phân đoạn chính xác như đã nhập (loại có độ chính xác tùy ý thay vì loại dấu chấm động). Nếu bạn xử lý toàn bộ số, hãy thực hiện điều đó integer. Ví dụ: bạn có thể tiết kiệm giá dưới dạng Cents.

  • amount ("Products" trong câu hỏi của bạn) đi vào bảng liên kết bill_product và thuộc loại numeric. Một lần nữa, integer nếu bạn xử lý toàn bộ số.

  • Bạn thấy phím ngoài trong bill_product? Tôi tạo cả hai để thay đổi tầng (ON UPDATE CASCADE): Nếu product_id hoặc bill_id nên thay đổi, thay đổi được xếp thành tất cả các mục nhập tùy thuộc trong bill_product và không có gì bị hỏng.
    Tôi cũng đã sử dụng ON DELETE CASCADE cho bill_id: Nếu bạn xóa một hóa đơn, chi tiết sẽ bị xóa với hóa đơn đó.
    Không như vậy đối với sản phẩm: Bạn không muốn xóa sản phẩm được sử dụng trong hóa đơn. Postgres sẽ ném một lỗi nếu bạn cố gắng này. Thay vào đó, bạn sẽ thêm cột khác vào product để đánh dấu các hàng quá cũ.

  • Tất cả các cột trong ví dụ cơ bản này kết thúc là NOT NULL, vì vậy giá trị NULL không được phép. (Có, tất cả cột - cột được sử dụng trong khóa chính được xác định UNIQUE NOT NULL tự động.) Đó là vì NULL giá trị sẽ không có ý nghĩa trong bất kỳ cột nào. Nó làm cho cuộc sống của người mới bắt đầu dễ dàng hơn. Nhưng bạn sẽ không thoát ra dễ dàng như vậy, bạn cần phải hiểu NULL handling. Các cột bổ sung có thể cho phép NULL giá trị, hàm và tham gia có thể giới thiệu các giá trị NULL trong truy vấn, v.v.

  • Đọc chương trên CREATE TABLE in the manual.

  • Các khóa chính được triển khai với một chỉ số duy nhất trên các cột chính giúp truy vấn nhanh chóng với các điều kiện trên cột PK. Tuy nhiên, chuỗi các cột chính có liên quan trong các khóa đa điểm. Vì PK trên bill_product nằm trên (bill_id, product_id) trong ví dụ của tôi, bạn có thể muốn thêm một chỉ mục khác chỉ trên product_id hoặc (product_id, bill_id) nếu bạn có các truy vấn tìm kiếm một số product_id và không có bill_id. Thông tin chi tiết:

  • Đọc chapter on indexes in the manual.

+22

Thưa bạn, bạn hoàn toàn tuyệt vời khi quay lại nhiều lần, ngay cả sau một vài tuần để cải thiện chất lượng câu trả lời của bạn. Tôi cảm ơn bạn vì đã là một người đóng góp chuyên dụng cho cộng đồng! –

+3

@RaduGheorghiu: Cảm ơn. Tôi đã được đề cập đến câu trả lời này một vài lần, vì vậy tôi tiếp tục tinh chỉnh nó. –

+0

Làm cách nào để tạo chỉ mục cho bảng ánh xạ 'bill_product'?Thông thường nó sẽ giống như: 'CREATE INDEX idx_bill_product_id ON reserved_rates (bill_id, product_id)'. Thê nay đung không? – codyLine

Các vấn đề liên quan