2017-04-22 63 views
3

我在创建oracle sql脚本时遇到了问题。我如何创建这两个约束?Oracle sql约束问题

  1. 如果VID是空值,则FID具有为空以及(VID =空 - > FID = NULL)
  2. 必须有中的一行,其中VID为null这也意味着FID必须是null,因为1.

这是我到目前为止有:

create table Employee(
Id int primary key, 
Name varchar(15) not null, 
VID int, 
FID int 

); 

Employee

+0

你是什么意思的“脚本”? (我什么也不假 - 从技术角度讲,你没有使用这个词 - 但是如果我错了,请解释一下。)然后,第一个约束是微不足道的 - 你尝试过什么?最后,第二个条件不能用约束来强制执行;约束条件是针对单个行而不是整个表上的条件。正如Gordon所说,一个解决方案可能是一个触发器;另一个是创建一个快速刷新提交的物化视图,它只是将空值的计数存储在VID中,并在物化视图上进行约束。 – mathguy

回答

0

你可以非常接近你想要的而没有触发器。

您可以使用检查约束第一:

create unique index unq_Employee_vid on 
    Employee(case when vid is null then -1 else id end); 

这一提法假定id非负,因为大部分:

alter table Employee add constraint chk_vid_fid 
    check (vid is not null or fid is null); 

可以使用的唯一约束做第二ids通常是。如果你使用的全方位整数值,那么我将明确一个字符串:

create unique index unq_Employee_vid on 
    Employee(case when vid is null then 'null vid' else cast(id as varchar2(255)) end); 

这保证最多一行其中vid是空的,而不是正好一行。您不能轻易拥有一个约束条件来确保只有一行具有值,因为空表与条件不匹配 - 并且在创建时表为空。

+1

'-1'是'id'(声明为'int')的有效值;一个无效的值,也许是'0.5',对于这种方法来说是一个更好的选择,因为它保证不会与有效的插入相冲突,无论多么不寻常。 – mathguy

+0

正如你自己所说的那样,这个解决方案不会**实现OP的要求。我刚刚发布了一个解决方案 - 使用物化视图。 – mathguy

0

以下是您可以如何执行您的要求 - 使恰好与VID is NULL一致的。正如我在你的原始问题的评论中所说的(戈登在他接受的答案中也说过),你不能仅仅因为约束而做这件事。但是,您可以使用物化视图来完成此操作。请注意,您必须使用refresh fast on commit创建MV,并且这需要基础表上的物化视图日志的某些内容。另外:如果你完全按照书面的方式尝试一切,MV上的约束将失败(当然,因为基表将是空的,所以不会有行,其中VIDNULL)。将行添加到基表中,其中有NULLVID,然后为commit事务,然后执行alter table命令将约束添加到MV。从那时开始,当且仅当它在VID列中留下一行NULL时,基表上的交易(包括一个或多个insert,delete,updatemerge陈述,随后一个commit)将经历。

一个古怪要记住:即使是Oracle的SQL语句ALTER MATERIALIZED VIEW,加上一个MV的约束,我们必须使用ALTER TABLE声明(与通过MV的名字),不ALTER MATERIALIZED VIEW

请注意,我使用名称t_Employee作为基表,因为我已经有一个表EMPLOYEE,我不想混淆我现有的对象。

create table t_Employee(
Id int primary key, 
Name varchar(15) not null, 
VID int, 
FID int 
); 

alter table t_Employee add constraint chk_vid_fid 
    check (vid is not null or fid is null) 
; 

create materialized view log on t_Employee 
with rowid 
(VID) 
including new values 
; 

create materialized view mv_Employee 
refresh fast on commit 
as select count(*) ct 
    from t_Employee 
    where VID is null 
; 

alter table mv_Employee add constraint chk_vid_ct 
    check (ct = 1) 
;