|
原帖由 yangtingkun 于 2010-7-8 11:59 发表 ![]()
怎么设计都会比较复杂:
CREATE TABLE products (
product_id NUMBER PRIMARY KEY
,product_name VARCHAR2(20)
,category VARCHAR2(20)
,primary key (product_id, category)
);
CREATE TABLE orders (
order_id NUMBER
,category VARCHAR2(20) ----- 假设一个订单只能订购某一种类别的产品
, primary key (order_id, category)
);
CREATE TABLE order_products ( ---- 每个订单包含哪些产品
order_id NUMBER
,category VARCHAR2(20)
,product_id NUMBER
,quantity NUMBER
,PRIMARY KEY (order_id,product_id)
,FOREIGN KEY (ORDER_ID, CATEGORY) REFERENCES ORDERS
,FOREIGN KEY (PRODUCT_ID, CATEGORY) REFERENCES PRODUCTS
);
其实完全靠约束是不可能解决所有数据问题的
虚拟列可以解决ORDER_PRODUCTS表数据的合法性问题,但是解决不了PRODUCTS表的合法性问题:
INSERT INTO products VALUES (7,'水彩笔','服装类');
这样一来你就有逻辑主键+业务主键构成的混合型主键,挺新颖的!
不过你也可以保留原来的id做逻辑主键,只要在id,category上再建唯一约束就可以了。代价就是会多一个索引。
这个'水彩笔'的例子也太霸道了吧,外键当然约束不了父表上的数据。不过有了这个外键之后,如果有人想在一批订货中包含'水彩笔'和其他文具,就会报错,从一定程度上也能帮助发现错误!
总结一下这个虚拟列作外键的用法,无非就是想在外键约束加入其他条件:
1. 如果这个条件可表示为同一行的列间关系:
在父表上可以用CASE表达式、甚至规则表达式凑出一个是否可用的标志位来。
在子表上同样可以用各种方法凑出标志位,如果不需要引用让它返回NULL, 如果需要引用而且合法则返回父表上的相同标志,如果不合法让它返回一个父表中没有的标记。
2. 如果这个条件是行间关系:想不出有什么办法。
3. 如果这个条件是表间关系:可以用伪装成DETERMINISTIC的函数,但由于它不是真正确定性的函数,所以有漏洞。
杨兄说那个delete_flag的例子其实更复杂,可否分享一下? |
|