Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql Oracle唯一约束-用于检查新关系中属性值的触发器_Sql_Database_Oracle_Triggers_Constraints - Fatal编程技术网

Sql Oracle唯一约束-用于检查新关系中属性值的触发器

Sql Oracle唯一约束-用于检查新关系中属性值的触发器,sql,database,oracle,triggers,constraints,Sql,Database,Oracle,Triggers,Constraints,嗨,我的sql语法不正确。我想创建一个唯一的约束,它查看新添加的外键,查看新相关实体的一些属性,以确定是否允许这种关系 CREATE or replace TRIGGER "New_Trigger" AFTER INSERT OR UPDATE ON "Table_1" FOR EACH ROW BEGIN Select "Table_2"."number" (CASE "Table_2"."number" > 0 THEN RAISE_APPLICATION_ERROR(-200

嗨,我的sql语法不正确。我想创建一个唯一的约束,它查看新添加的外键,查看新相关实体的一些属性,以确定是否允许这种关系

CREATE or replace TRIGGER "New_Trigger"
AFTER INSERT OR UPDATE ON "Table_1" 
FOR EACH ROW
BEGIN
Select "Table_2"."number" 
(CASE "Table_2"."number" > 0
  THEN RAISE_APPLICATION_ERROR(-20000, 'this is not allowed');
END)
from "Table_1"
WHERE "Table_2"."ID" = :new.FK_Table_2_ID 
END;
编辑:APC的答案非常全面,但是让我觉得我做得不对

情况是,我有一个具有不同权限级别的人员表,我想检查这些权限级别,例如,用户“Bob”具有低级别权限,他试图成为需要高权限的部门主管,因此系统会防止这种情况发生



还有一个后续问题,提出了一个相关的场景,但数据模型不同

不要使用触发器创建唯一约束或外键约束。Oracle对唯一键和外键提供声明式支持,例如:

在列上添加唯一约束:

ALTER TABLE "Table_1" ADD (
  CONSTRAINT table_1_uk UNIQUE (column_name)
);
添加外键关系:

ALTER TABLE "ChildTable" ADD (
  CONSTRAINT my_fk FOREIGN KEY (parent_id)
    REFERENCES "ParentTable" (id)
);
我不清楚你到底想用触发器实现什么-它有点混乱,SQL和PL/SQL混在一起不起作用,而且似乎引用了
“Table_2”
上的一列,实际上没有被查询

一个好的经验法则是,如果您的触发器正在查询触发器所在的同一个表,那么它可能是错误的


我不确定,但你是在追求某种有条件的外键关系吗?i、 e.“仅允许父级满足条件x的子行”?如果是这样,问题就出在数据模型中,应该在那里解决。如果您提供更多关于您试图实现的目标的解释,我们应该能够帮助您。

不要使用触发器来创建唯一约束或外键约束。Oracle对唯一键和外键提供声明式支持,例如:

在列上添加唯一约束:

ALTER TABLE "Table_1" ADD (
  CONSTRAINT table_1_uk UNIQUE (column_name)
);
添加外键关系:

ALTER TABLE "ChildTable" ADD (
  CONSTRAINT my_fk FOREIGN KEY (parent_id)
    REFERENCES "ParentTable" (id)
);
我不清楚你到底想用触发器实现什么-它有点混乱,SQL和PL/SQL混在一起不起作用,而且似乎引用了
“Table_2”
上的一列,实际上没有被查询

一个好的经验法则是,如果您的触发器正在查询触发器所在的同一个表,那么它可能是错误的


我不确定,但你是在追求某种有条件的外键关系吗?i、 e.“仅允许父级满足条件x的子行”?如果是这样,问题就出在数据模型中,应该在那里解决。如果您提供更多关于您试图实现的目标的解释,我们应该能够帮助您。

因此,您要执行的规则是,如果表2中的某列为零或更少,则表1只能引用表2。六羟甲基三聚氰胺六甲醚。。。。让我们整理一下触发器逻辑,然后讨论规则

触发器应如下所示:

CREATE or replace TRIGGER "New_Trigger"
AFTER INSERT OR UPDATE ON "Table_1" 
FOR EACH ROW
declare
  n "Table_2"."number".type%;
BEGIN

    Select "Table_2"."number" 
    into n
    from "Table_2"
    WHERE "Table_2"."ID" = :new.FK_Table_2_ID; 

    if n > 0
    THEN RAISE_APPLICATION_ERROR(-20000, 'this is not allowed');
    end if;

END;
请注意,在插入或更新表上的多行时,错误消息应包括一些有用的信息,例如表_1主键的值


这里您要做的是强制执行一种称为断言的约束类型。断言是在ANSI标准中指定的,但Oracle尚未实现它们。任何其他关系数据库也没有达到这一点

断言是有问题的,因为它们是对称的。也就是说,还需要在表2上强制执行该规则。在表1中创建记录时检查规则的时刻。假设稍后某个时间某个用户更新了表_2.NUMBER,使其大于零:您的规则现在已被破坏,但您不会知道它已被破坏,直到有人对表_1进行了完全不相关的更新,然后更新将失败。恶心

那么,该怎么办

如果规则是

只有在以下情况下,表_1才能引用表_2 表2.1的数字为零

然后,您可以在不使用触发器的情况下强制执行它

  • 在表2上为(ID、编号)添加唯一约束;您需要一个额外的约束,因为ID仍然是表2的主键
  • 在表_1上添加一个名为表_2_NUMBER的伪列。将其默认为零,并具有检查约束以确保其始终为零。(如果你在11G上,你应该考虑使用一个虚拟列。)
  • 更改表_1上的外键,以便(FK_表_2_ID,表_2_编号)引用唯一约束,而不是表_2的主键
  • 放下“新触发器”触发器;您不再需要它,因为外键将阻止任何人将表_2.NUMBER更新为零以外的值 但是如果这个规则真的是我在顶部制定的,即

    只有在以下情况下,表_1才能引用表_2 表2.数值不大于零(即负值可以)

    然后,您需要另一个触发器,这次是在表2上,以在规则的另一端强制执行它

    CREATE or replace TRIGGER "Assertion_Trigger"
    BEFORE UPDATE of "number" ON "Table_2" 
    FOR EACH ROW
    declare
      x pls_integer;
    BEGIN
    
        if :new."number"  > 0
        then
            begin
                Select 1 
                into x
                from "Table_1"
                WHERE "Table_1"."FK_Table_2_ID" = :new.ID
                and rownum = 1;
    
               RAISE_APPLICATION_ERROR(-20001, :new.ID
                     ||' has dependent records in Table_1');
            exception
               when no_data_found then 
                   null; -- this is what we want
            end;
    
    END;
    

    如果表_2中的记录引用了表_2.NUMBER,则此触发器将不允许您将其更新为大于零的值。它仅在UPDATE语句触及表2.NUMBER时触发,以最小化执行查找对性能的影响

    因此,您要强制执行的规则是,如果表2中的某些列为零或更少,则表1只能引用表2。六羟甲基三聚氰胺六甲醚。。。。让我们整理一下触发器逻辑,然后讨论规则

    触发器应如下所示:

    CREATE or replace TRIGGER "New_Trigger"
    AFTER INSERT OR UPDATE ON "Table_1" 
    FOR EACH ROW
    declare
      n "Table_2"."number".type%;
    BEGIN
    
        Select "Table_2"."number" 
        into n
        from "Table_2"
        WHERE "Table_2"."ID" = :new.FK_Table_2_ID; 
    
        if n > 0
        THEN RAISE_APPLICATION_ERROR(-20000, 'this is not allowed');
        end if;
    
    END;
    
    请注意,在插入或更新表上的多行时,错误消息应包括一些有用的信息,例如表_1主键的值


    这里您要做的是强制执行一种称为断言的约束类型。断言是在ANSI标准中指定的,但Oracle尚未实现它们。任何其他关系数据库也没有达到这一点

    断言是有问题的,因为它们是对称的。也就是说,还需要在表2上强制执行该规则。在表1中创建记录时检查规则的时刻。苏