2017-04-22 93 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) 
;