你已經有一個資料庫,也有一些資料表。甚至你已經把資料表填好資料了。現在是時候來顧一下這些資料的完整性啦。
在每個 schema 裡面創建資料表時,系統會自動幫你加上指向同一個 schema 其他表的 foreign keys。現在你要做的是把不同 schema 的表連起來——加上跨 schema 的 foreign keys。
舉例來說,order 這個 schema 裡的 order 表會指向 user schema 裡的 account 表。你要幫這個表加一個 foreign key。SQL 大概會長這樣:
ALTER TABLE "order".order
ADD CONSTRAINT fk_order_user
FOREIGN KEY (user_id)
REFERENCES "user".account(id)
ON DELETE RESTRICT;
Foreign Keys 清單
總共你要加 40 個 foreign keys :)
product schema:
[product].review.user_id → [user].account.id
商品評論要連到發表評論的使用者。
[product].question.user_id → [user].account.id
商品問題是註冊用戶才能問的。
[product].answer.user_id → [user].account.id
回答也是屬於某個用戶。
order schema:
[order].order.user_id → [user].account.id
下單的人一定是註冊用戶。
[order].order_item.product_id → [product].product.id
訂單項目一定要指向一個商品。
[order].order_item.variant_id → [product].variant.id
如果有選商品的 variant,就必須存在。但 variant 被刪除時,這欄會變成 NULL。
[order].cart.user_id → [user].account.id
購物車屬於某個特定用戶。
[order].cart_item.product_id → [product].product.id
購物車裡的商品必須是有效的商品。
[order].cart_item.variant_id → [product].variant.id
如果有選 variant 就要存在,被刪除時欄位會變 NULL。
logistics schema:
[logistics].inventory.variant_id → [product].variant.id
variant 可能會被刪掉(例如停售)。
[logistics].inventory_movement.product_id → [product].product.id
倉庫的任何移動都要對應到實際商品。
[logistics].inventory_movement.variant_id → [product].variant.id
移動可以是針對某個商品 variant。
[logistics].stock_level.product_id → [product].product.id
庫存水準是根據現有商品設定的。
[logistics].transfer.product_id → [product].product.id
移動只針對真的存在的商品。
[logistics].transfer.variant_id → [product].variant.id
variant 可能會被刪掉。
[logistics].package.order_id → [order].order.id
每個包裹都要連到一個訂單。
payment schema:
[payment].payment_transaction.order_id → [order].order.id
付款交易一定要對應到訂單。
[payment].invoice.order_id → [order].order.id 發票是根據訂單開的。
[payment].billing_address.user_id → [user].account.id
帳單地址屬於某個用戶。
[payment].wallet.user_id → [user].account.id
錢包對每個用戶都是唯一的。
marketing schema:
[marketing].discount.product_id → [product].product.id
折扣可以綁定到某個商品。
[marketing].discount.category_id → [product].category.id
折扣也可以綁定到商品分類。
[marketing].discount.brand_id → [product].brand.id
品牌折扣。
[marketing].promo_usage.user_id → [user].account.id
只有註冊用戶才能用優惠碼。
[marketing].featured_product.product_id → [product].product.id
首頁精選商品必須存在。
[marketing].referral_use.referrer_id → [user].account.id
邀請人一定要是用戶。
[marketing].referral_use.referee_id → [user].account.id
被邀請的人也是必須的用戶。
support schema:
[support].support_ticket.user_id → [user].account.id
每個客服單都是用戶創的。
[support].support_ticket.category_id → [support].ticket_category.id
客服單的分類可以被刪掉,單子還會留著。
[support].ticket_message.sender_id → [user].account.id
訊息是用戶(或 agent,如果他們也在 user.account)發的。
[support].support_agent.user_id → [user].account.id
客服 agent 也是用戶。
[support].ticket_status_log.changed_by → [user].account.id
記錄誰改了狀態(用戶或員工)。
content schema:
[content].article.author_id → [user].account.id
文章是註冊用戶寫的。
[content].media.uploaded_by → [user].account.id
誰上傳的媒體檔案(可能被刪掉)。
[content].content_revision.author_id → [user].account.id
誰改的內容(可能被刪掉)。
備註
只要可以的話,建議用 ON DELETE SET NULL,這樣刪掉某個 entity 時,關聯資訊不會完全消失。
如果是用 "target_type/target_id" 這種方式連 entity(像 user.comment),SQL 層級沒辦法設 foreign key,這種關聯要靠應用程式層級自己控。
這份清單涵蓋了 SQL 層級基本資料完整性需要的主要跨 schema 關聯。
包含解決方案的檔案。
GO TO FULL VERSION