我有下表。
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 :(得分:4)
您可以创建基于函数的唯一索引来强制执行此类操作。您无法创建约束。
这利用了Oracle b-tree索引不对NULL数据编制索引的事实,因此索引只包含studclass_status
为E
的行的条目。
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 );
答案 1 :(得分: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;
答案 2 :(得分:1)
您应该可以使用partial unique index执行此操作。为了确保每个ssn只有一个注册类,这应该可以工作:
CREATE UNIQUE INDEX ssn_enrollments ON class_has_students(per_ssn)
WHERE studclass_status='E';
请注意,并非所有SQL实现都支持此功能,但至少从版本8开始支持PostgreSQL。