2012-07-29 37 views
0

我有下表。PL/SQL - 一個人只有一個值

CLASS_HAS_STUDENTS (
    PER_SSN INTEGER NOT NULL, 
    PER_YEAR INTEGER NOT NULL, /*These two are PKs for a student*/ 
    SCHOOL_CODE INTEGER NOT NULL, /*PK for a school*/ 
    CLASS_YEAR INTEGER NOT NULL, 
    CLASS_NUMBER INTEGER NOT NULL, 
    CLASS_TEACHTYPE CHAR(3) NOT NULL, /*These three are PKs for a class*/ 
    STUDCLASS_STATUS CHAR(1) NOT NULL 
     constraint CKC_STUDCLASS_STATUS_CLASS_TI check (StudClass_Status IN ('E', 'Y', 'T', 'P', 'F')), 
    STUDCLASS_LISTNUMBER INTEGER NOT NULL, 
    STUDCLASS_ROLLNUMBER INTEGER NOT NULL 
); 

(此代碼缺少一些細微的約束)

現在,我需要一種方法來檢查一個PER_SSN/PER_YEAR(一個人的PK)只能有一個「E」(「已登記」)狀態。我不能用觸發器來做到這一點(因爲我從同一張表中選擇),我不知道我是否可以使用檢查約束(我可以在這裏使用COUNT()?)。任何幫助表示讚賞。

+0

我想你可以用'BEFORE INSERT'觸發器來做到這一點。做一個'count',如果有什麼不對的話'raise_application_error'。你嘗試過嗎? – 2012-07-29 20:47:08

+0

哦,完全沒有!我可以在插入前做到這一點嗎?如果是這樣,那麼這一切都解決了。我會去檢查一下,謝謝! – 2012-07-29 20:48:11

回答

4

你可以創建一個基於函數的唯一索引來執行這種事情。你不能像這樣創建一個約束。

這充分利用了Oracle b-tree索引不索引NULL數據的情況,因此索引只會包含studclass_statusE的行的條目。

CREATE UNIQUE INDEX idx_one_enrolled 
    ON class_has_students(CASE WHEN studclass_status = 'E' 
           THEN per_ssn 
           ELSE null 
          END, 
          CASE WHEN studclass_status = 'E' 
           THEN per_year 
           ELSE null 
          END); 
+0

因此,這個指數應該採取一個人(SSN + YEAR),並檢查一個'E'是否已經存在這個人,我是否正確? – 2012-07-29 20:55:47

+0

@ user1231958 - 僅當'studclass_status'爲'E'時,它才創建一個唯一的索引來索引'per_ssn'和'per_year'值。這將防止兩行具有相同的'per_ssn'和'per_year'值,其中'studclass_status'在兩行中都是'E'被插入。它在概念上類似於部分唯一索引,Oracle不支持部分唯一索引語法。 – 2012-07-29 20:58:20

+0

我會以此爲答案,非常感謝! – 2012-07-29 20:58:56

1

我對你的問題有點困惑。我猜你要麼需要:

1)防止插入的每名學生一個以上的狀態(在這種情況下,觸發將是合適的)

2)使用SELECT聲明找同學已經在表,在這種情況下,你想要做的事,如:

SELECT PER_SSN, PER_YEAR, STUDCLASS_STATUS, COUNT(*) 
FROM CLASS_HAS_STUDENTS 
WHERE STUDCLASS_STATUS = 'E' 
HAVING COUNT(*) > 1 
GROUP BY PER_SSN, PER_YEAR, STUDCLASS_STATUS; 
+0

我想防止爲每個學生插入多個「E」狀態。一個觸發器將是適當的,但從我的理解,我不能在我檢查的同一張桌子上做選擇。 – 2012-07-29 20:49:22

1

你應該能夠用做到這一點。爲了確保您只有一個班就讀,每SSN這應該工作:

CREATE UNIQUE INDEX ssn_enrollments ON class_has_students(per_ssn) 
WHERE studclass_status='E'; 

注意,這個功能在所有SQL實現支持,但由於至少版本的PostgreSQL已經支持8

+0

此語法在Oracle中是無效的,這是標記問題的內容。 – 2012-07-29 20:51:44

+0

Mea culpa。我誤解了pl/sql作爲pgsql。儘管解決方案仍然有效,我看到Justin Cave提供了一個Oracle變體。 – 2012-07-29 20:53:37