Primary-Key

為什麼無法強制執行預期的完整性約束?

  • May 7, 2018

以下完整性約束試圖強制執行什麼?(完整性約束是主鍵並在這種情況下進行檢查,但我不明白我應該真正寫什麼)。

解釋為什麼不能強制執行預期的完整性約束?

CREATE TABLE Sailors
( sid INTEGER,
 sname CHAR(10),
 rating INTEGER,
 age REAL,
 PRIMARY KEY (sid),
 CHECK
   ( (SELECT COUNT (S.sid) FROM Sailors S)
   + (SELECT COUNT (B.bid) FROM Boats B) < 100 )
) ;

我們在學校學習 SQL。

問候 Sabancı 電腦 @yguney

(注意:你在這個表上聲明了兩個約束,一個PRIMARY KEY約束和一個CHECK約束。答案是關於第二個。)

CHECK約束試圖強制執行:

兩個表中的行數應小於 100

因此,它應該 - 如果它有效 - 允許一個表有 50 行,其他 49 行,或 1 和 98 或 5 和 10 或……但沒有一個應該有 100 或更多。如果一個有 90,另一個應該不超過 9,並且任何嘗試插入更多行的事務都應該被拒絕(引發約束錯誤)。

至少這就是它看起來正在嘗試做的事情。現在的問題或者更確切地說是約束的兩個問題:

  • CHECK幾乎所有實現中,約束都是行約束。因此,它會檢查插入或更新的**每一行。**這是一個實現問題,目前的 DBMS 沒有實現涉及子查詢的約束(Firebird 除外,它聲稱這樣做,但我還沒有測試過)。

有一些 DBMS 允許在CHECK約束中使用函式(並且函式可以包含子查詢),因此可以“解決”限制,但這會導致各種並發問題並且問題並沒有真正解決。即使在那些 DBMS 中,建議也不要在CHECK約束中包含子查詢。

在我看來,涉及表的許多行(在本例中為所有行)的約束應該是ASSERTION,而不是CHECK約束。

  • 第二個也是更嚴重的是CHECK約束是對一個表的約束。它不是一個ASSERTION(那些是可以跨越多個表的約束)。

因此,即使有一個允許CHECK使用子查詢進行約束的實現,結果也將是人們所期望的。Sailors理解原因的一種方法是,只有在插入或更新行時才會檢查約束。這將導致這些有問題的情況:

Boats我們在表中插入 200 行。將不會檢查約束,因此允許這樣做。然後我們嘗試在Sailors. 檢查約束並禁止該行。但是我們是否設法執行了我們的意圖?不是,因為兩張表加起來是200行,也就是100多行。

我們在 中插入 5 行Sailors。到目前為止沒有問題。然後表中有 200 行Boats。約束將再次像以前一樣不被檢查,以便允許。然後我們嘗試更新Sailors. 檢查約束,我們得到一個錯誤。UPDATE失敗。但是我們總共還有 205 行,那為什麼更新會失敗呢?

作為結論,這個約束有兩個問題。首先,目前的實現不允許約束中的子查詢,CHECK其次它應該是一個約束ASSERTION而不是CHECK約束,因為它涉及多個表。

請注意,ASSERTION到目前為止還沒有一個 DBMS 實現(至少是那些基於 SQL 的,還有一些基於 Tutorial D 的。)

引用自:https://dba.stackexchange.com/questions/205152