通用数据库规范化

General database normalization

假设我有 table 种产品卖给我的客户。

每条记录都有一个productID 和productName。

我可以向每个客户销售超过 1 种产品,但我想让客户只能订购某些产品。

那些 table 会是什么样子?

这是我目前拥有的:

PRODUCTS
+------------+-------------+
| PROD_ID    |  PROD_NAME  |
+------------+-------------+

CUSTOMER
+------------+-------------+
| CUST_ID    |  CUST_NAME  |
+------------+-------------+

ORDERS
+------------+-------------+
| ORDER_ID   |  CUST_ID    |
+------------+-------------+

我用 PostgreSQL 编写并测试了它,但原理对于任何 SQL dbms 都是相同的。

产品和客户的表格很简单。

create table products (
  prod_id integer primary key,
  prod_name varchar(35) not null
);
insert into products values 
(1, 'Product one'), (2, 'Product two'), (3, 'Product three');

create table customers (
  cust_id integer primary key,
  cust_name varchar(35) not null
);
insert into customers values 
(100, 'Customer 100'), (200, 'Customer 200'), (300, 'Customer 300');

table "permitted_products" 控制每个客户可以订购哪些产品。

create table permitted_products (
  cust_id integer not null references customers (cust_id),
  prod_id integer not null references products (prod_id),
  primary key (cust_id, prod_id)
);
insert into permitted_products values 
-- Cust 100 permitted to buy all three products
(100, 1), (100, 2), (100, 3),
-- Cust 200 permitted to buy only product 2.
(200, 2);

客户 300 没有允许的产品。

create table orders (
  ord_id integer primary key,
  cust_id integer not null references customers (cust_id)
);
insert into orders values
(1, 100), (2, 200), (3, 100);

table "order_line_items" 是 "magic" 发生的地方。 {cust_id、prod_id} 上的外键约束可防止在未经许可的情况下订购产品。

create table order_line_items (
  ord_id integer not null,
  line_item integer not null check (line_item > 0),
  cust_id integer not null,
  prod_id integer not null,
  foreign key (ord_id) references orders (ord_id),
  foreign key (cust_id, prod_id) references permitted_products (cust_id, prod_id),
  primary key (ord_id, line_item)
);

insert into order_line_items values
(1, 1, 100, 1), (1, 2, 100, 2), (1, 3, 100, 3);
insert into order_line_items values
(2, 1, 200, 2);
insert into order_line_items values
(3, 1, 100, 3);

您可以开始为客户 300 下订单。 . .

insert into orders values (4, 300);

。 . .但您不能插入任何订单项。

insert into order_line_items values (4, 1, 300, 1);
ERROR:  insert or update on table "order_line_items" violates foreign key constraint "order_line_items_cust_id_fkey"
DETAIL:  Key (cust_id, prod_id)=(300, 1) is not present in table "permitted_products".