将用户定义的约束添加到SQL表

时间:2017-06-18 09:43:32

标签: java sql oracle

所以我正在使用2张桌子:人和婚姻。 人拥有许多属性,他的PK是person_id。 Marrige的定义如下:

AppCompatActivity

我想在此表中添加一个约束,所以我添加了这个(TODO:Parent.age> Child.age):

ActionBarActivity

现在当我试图将它附加到Marriage表时这样做:

CREATE TABLE Marriage(Person_id NUMBER(6) PRIMARY KEY REFERENCES Persons(Person_id)
, Relative_id NUMBER(4) REFERENCES Persons(Person_id)
, Relationship_type VARCHAR(20) NOT NULL CHECK (Relationship_type IN('Wife', 'Husband', 'Child'))
)

我收到以下错误:

CREATE FUNCTION fn_OlderThanSon (
    @Parent NUMBER
    @Child NUMBER
)
RETURNS VARCHAR(10)
AS
BEGIN
    IF EXISTS (SELECT Person_id FROM Persons WHERE Person_id = @Parent)
AND EXISTS (SELECT Person_id FROM Persons WHERE Person_id = @Child)
        return 'True'
    return 'False'
END

所以,我做错了什么?甚至可以做这样的逻辑约束吗?

2 个答案:

答案 0 :(得分:1)

您希望使用函数fn_OlderThanSon()来确保“父级”类型的记录比“子级”类型的记录旧:if (Person_id.age>Relative_id.age)

这样的业务规则需要一个断言 - 一个声明性的多行约束 - 而不是一个简单的检查约束。目前Oracle不支持CREATE ASSERTION(尽管有an initiative to make this happen)。

现在,要强制执行这样的规则需要过程逻辑,可以通过Persons表上的PL / SQL API直接调用,也可以通过触发器间接调用。触发器将是复杂的,因为您必须解决变异表问题(您需要查询您正在积极更改的表中的记录),但许多人不喜欢屏蔽PL / SQL过程背后的表。

答案 1 :(得分:0)

不支持您希望它的工作方式。你有几个选择:

  1. 您可以编写一个触发器,在插入/更新之前触发并执行此检查。如果结果不合适,则抛出错误。

  2. 如果根据功能一切正常,您可以在存储过程中进行插入。并通过该存储过程进行插入。

  3. 您可以在应用程序级别进行检查,只有在一切正常时才调用插入。

  4. 从纯科学的角度来看,第二种和第三种选择的结合是可取的。如果您需要紧急做一些事情,那么第一个选项会让您头疼,因为他们知道结果会很好。

    但是,您还需要应对不同的场景。如果插入/更新了孩子,除了将孩子的年龄与孩子的年龄进行比较之外,您还需要检查孩子是否会比他/她的父母年龄大。此外,您可能需要合法地更新父级和子级的年龄,但顺序不是可交换的。

    示例:父母是40岁,孩子是20岁。您需要将父级更新为61,将子级更新为41.如果以错误的方式执行此操作,即将父级的年龄从40更改为尚未更改为41岁,则通过根据您当前的业务规则,触发/存储过程将不会成功。