通用数据库规范化
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".
假设我有 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".