Bạn có database, bạn có các bảng. Và bạn thậm chí đã đổ dữ liệu vào các bảng đó rồi. Giờ là lúc nghĩ về việc đảm bảo tính toàn vẹn của dữ liệu này.
Khi tạo bảng trong mỗi schema, các foreign keys tới các bảng cùng schema đã được thêm tự động. Giờ bạn cần liên kết các bảng giữa các schema khác nhau - thêm foreign keys.
Ví dụ bảng order trong schema order tham chiếu tới user trong bảng account của schema user. Bạn cần thêm foreign key cho bảng này. Câu lệnh có thể như sau:
ALTER TABLE "order".order
ADD CONSTRAINT fk_order_user
FOREIGN KEY (user_id)
REFERENCES "user".account(id)
ON DELETE RESTRICT;
Danh sách foreign keys
Tổng cộng bạn sẽ cần thêm 40 foreign keys :)
Schema product:
[product].review.user_id → [user].account.id
Đánh giá sản phẩm phải liên kết với user đã để lại đánh giá đó.
[product].question.user_id → [user].account.id
Câu hỏi về sản phẩm được hỏi bởi user đã đăng ký.
[product].answer.user_id → [user].account.id
Câu trả lời cũng thuộc về user.
Schema order:
[order].order.user_id → [user].account.id
User đặt hàng — luôn là user đã đăng ký.
[order].order_item.product_id → [product].product.id
Mỗi item trong order luôn tham chiếu tới một sản phẩm cụ thể.
[order].order_item.variant_id → [product].variant.id
Nếu chọn variant của sản phẩm — nó phải tồn tại. Nhưng variant có thể bị xóa (lúc đó trường sẽ thành NULL).
[order].cart.user_id → [user].account.id
Giỏ hàng thuộc về một user cụ thể.
[order].cart_item.product_id → [product].product.id
Sản phẩm trong giỏ phải là sản phẩm hợp lệ.
[order].cart_item.variant_id → [product].variant.id
Variant được chọn phải tồn tại nếu có. Nếu bị xóa — trường thành NULL.
Schema logistics:
[logistics].inventory.variant_id → [product].variant.id
Variant có thể bị xóa (ví dụ ngừng bán).
[logistics].inventory_movement.product_id → [product].product.id
Mọi chuyển động kho đều liên quan tới sản phẩm thực tế.
[logistics].inventory_movement.variant_id → [product].variant.id
Loại chuyển động có thể theo variant cụ thể.
[logistics].stock_level.product_id → [product].product.id
Mức tồn kho được xác định theo sản phẩm hiện có.
[logistics].transfer.product_id → [product].product.id
Chuyển kho chỉ áp dụng cho sản phẩm thực tế.
[logistics].transfer.variant_id → [product].variant.id
Variant có thể bị xóa.
[logistics].package.order_id → [order].order.id
Mỗi package liên kết với một order cụ thể.
Schema payment:
[payment].payment_transaction.order_id → [order].order.id
Giao dịch thanh toán luôn liên quan tới order.
[payment].invoice.order_id → [order].order.id Hóa đơn được tạo cho order.
[payment].billing_address.user_id → [user].account.id
Địa chỉ thanh toán thuộc về user.
[payment].wallet.user_id → [user].account.id
Ví là duy nhất cho mỗi user.
Schema marketing:
[marketing].discount.product_id → [product].product.id
Discount có thể gắn với một sản phẩm cụ thể.
[marketing].discount.category_id → [product].category.id
Discount có thể gắn với category sản phẩm.
[marketing].discount.brand_id → [product].brand.id
Discount cho brand.
[marketing].promo_usage.user_id → [user].account.id
Promo code chỉ dùng bởi user đã đăng ký.
[marketing].featured_product.product_id → [product].product.id
Sản phẩm nổi bật trên trang phải tồn tại.
[marketing].referral_use.referrer_id → [user].account.id
Người mời — user bắt buộc.
[marketing].referral_use.referee_id → [user].account.id
Người được mời — user bắt buộc.
Schema support:
[support].support_ticket.user_id → [user].account.id
Mỗi ticket được tạo bởi user.
[support].support_ticket.category_id → [support].ticket_category.id
Category của ticket có thể bị xóa, ticket vẫn còn.
[support].ticket_message.sender_id → [user].account.id
Tin nhắn được gửi bởi user (hoặc agent nếu họ cũng trong user.account).
[support].support_agent.user_id → [user].account.id
Agent support — luôn là user.
[support].ticket_status_log.changed_by → [user].account.id
Lưu lại ai đã đổi trạng thái (user hoặc nhân viên).
Schema content:
[content].article.author_id → [user].account.id
Bài viết được viết bởi user đã đăng ký.
[content].media.uploaded_by → [user].account.id
Ai upload media (có thể bị xóa).
[content].content_revision.author_id → [user].account.id
Ai sửa đổi (có thể bị xóa).
Lưu ý
Ở đâu có thể, nên dùng ON DELETE SET NULL để khi xóa entity thì thông tin liên kết không bị mất hoàn toàn.
Đối với liên kết entity kiểu "target_type/target_id" (ví dụ user.comment), foreign key không thể dùng ở mức SQL, các liên kết này phải kiểm soát ở tầng ứng dụng.
Danh sách này bao gồm các liên kết cross-schema cơ bản để đảm bảo tính toàn vẹn dữ liệu ở mức SQL.
Tệp có giải pháp.
GO TO FULL VERSION