PL / SQL - 一个人只有一个值

时间:2012-07-29 20:42:27

标签: sql oracle plsql

我有下表。

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()吗?)。任何帮助表示赞赏。

3 个答案:

答案 0 :(得分: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 );

答案 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。