如何在Oracle WITHOUT PL / SQL中创建此约束

时间:2012-04-09 18:47:14

标签: sql oracle constraints

这是我的玩具设置。我有3张桌子。一张桌子是客人名单(姓氏,名字,等等),食物清单(豆类,糊状,米饭,蔬菜)和订单清单(客人ID,食品ID)。订单清单是我感兴趣的清单。我想限制它以满足以下条件。

客人必须拥有3个订单。 客人可以订购空订单。 除非订单为空,否则每位客人的订单不能相同。

因此订单表看起来如下(使用字符串而不是fk ID):

steve, beans
steve, rice
steve, veggies
joey, rice
joey, beans
joey, <null>
sarah, rice
sarah, <null>
sarah, <null>
sam, <null>
sam, <null>
sam, <null>

显然Sam不喜欢食物......但那将是一张有效的餐桌。每个用户都有3个条目,没有用户有重复项(没有双重bean!)。

我尝试过的事情

create table order (
  guest_uid FK,
  food_uid FK,
  CONSTRAINT order_unique UNIQUE (guest_uid, food_uid)
)

这适用于验证没有双豆,但是double / triple null不会飞。我希望oracle unique null适用于此处,但我猜不会(违反了唯一约束order_unique)。

我尝试了一些其他检查约束,但我无法找到一种方法来指定跨行的唯一性而不执行子查询(当然不允许)。有什么想法吗?感谢

PS。如果唯一有效的答案是“使用PL / SQL或触发器”,我将确保标记正确的答案。

2 个答案:

答案 0 :(得分:4)

您可以使用基于函数的索引来强制跨行的唯一性(请注意,我调用了表guest_food,因为order是保留字

create unique index idx_order_unique
    on guest_food( case when food_uid is not null
                        then guest_uid
                        else null
                    end,
                   case when food_uid is not null
                        then food_uid
                        else null
                    end );

这将允许您为任何特定NULL添加food_uid guest_uid的行数,同时禁止重复的非NULL值。

要求每个guest虚拟机在guest_food表中只有三行,这不是您可以使用约束强制执行的操作。您可以创建一个物化视图,在提交时执行快速刷新,存储每guest_uid个行数的计数,并添加一个约束,如果该计数不是3,则会引发错误。但这通常是想要强制实施这一点非常不寻常,所以它会让我怀疑数据模型有点偏差。

答案 1 :(得分:1)

您是否考虑过更改数据结构?由于订单中只有三个项目,因此转动项目:

create table order 
(
    guest_uid FK,
    food_uid1 FK,
    food_uid2 FK,
    food_uid3 FK
) 

然后,您可以为每个food_uid添加约束,以确保外键正确。

然后,您可以添加一个检查约束,以满足除NULL之外没有重复的要求。