Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/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
Oracle 一对常数关系的建模_Oracle_Database Design - Fatal编程技术网

Oracle 一对常数关系的建模

Oracle 一对常数关系的建模,oracle,database-design,Oracle,Database Design,一对常数关系是否可以在Oracle中完全建模并带有约束?换句话说,父实体始终具有子实体的n个子实体,并且每个子实体只有一个父实体 将n看作一个数据库常量。我不知道如何。这是一个古老的问题:“先来的是鸡还是蛋?”。当尚未添加子项时,如何约束父项,以及如何在没有父项的情况下添加子项 您可以创建一个名为“ValidParents”的新表,该表只有N个子项的父ID,并将其与触发器保持同步。这可能不是您想要的,但我有一个方法可以执行类似的操作 通常一对多的安排是这样的: Primary Table: pr

一对常数关系是否可以在Oracle中完全建模并带有约束?换句话说,父实体始终具有子实体的n个子实体,并且每个子实体只有一个父实体


将n看作一个数据库常量。

我不知道如何。这是一个古老的问题:“先来的是鸡还是蛋?”。当尚未添加子项时,如何约束父项,以及如何在没有父项的情况下添加子项


您可以创建一个名为“ValidParents”的新表,该表只有N个子项的父ID,并将其与触发器保持同步。

这可能不是您想要的,但我有一个方法可以执行类似的操作

通常一对多的安排是这样的:

Primary Table:
primary_id (PK)
primary_stuff

Secondary Table:
secondary_id (PK)
primary_id (FK)
secondary_stuff
建立严格的一对一模型的替代方案是:

Primary Table:
primary_id (PK)
secondary_id (FK, non-null)
primary_stuff

Secondary Table:
secondary_id (PK)
secondary_stuff
这可能有点奇怪,但它是有效的。在一对多和一对一的情况下,这种方法的一种变体可能很有用,例如一个客户有多个地址,但只有一个账单地址。

基于早期的“鸡+蛋”点,您可以创建延迟约束,直到提交时才验证这些约束。。。这些可能有用吗

e、 g


即使在多个会话进行更新时,这样做也是不容易的。如果您尝试使用触发器,您将陷入混乱,而Oracle的声明性约束不足以表达这一点

可按如下方式进行:-

  • 在父表和子表上创建物化视图日志
  • 创建一个物化联接视图,将它们联接在一起,并统计按父级分组的子级数。这必须在提交时快速刷新
  • 在物化联接视图上设置一个约束,子记录的计数必须等于“n”(数据库常量)
  • 然后可以执行一系列insert/update/delete语句。当您提交时,物化视图将刷新,如果不满足条件,您将在该点上得到一个约束冲突错误


    一个额外的技巧是只将未通过约束的行包含到物化视图中(具有count(ChildId)5),这样就不会浪费任何存储空间。

    解决鸡和蛋问题的另一种方法是使用INSERT ALL。因为它是一条语句,所以不需要延迟外键约束。它还提供了一种插入确切数量的依赖行的机制。附加约束阻止插入附加行。但是我们需要一个带有外键的辅助表,以防止意外删除感兴趣的行

    在本例中,n=3

    SQL> create table parent
      2   ( pk_col number not null
      3     , col1 varchar2(20)
      4     , constraint par_pk primary key (pk_col)
      5    )
      6  /
    
    Table created.
    
    SQL> 
    SQL> create table child
      2   ( pk_col number not null
      3     , seqno number(1,0) not null
      4     , col2 date
      5     , constraint ch_pk primary key
      6          (pk_col, seqno)
      7     , constraint ch_par_fk foreign key
      8          (pk_col) references parent (pk_col)
      9     , constraint ch_ck check (seqno between 1 and 3)
     10    )
     11  /
    
    Table created.
    
    SQL> 
    SQL> create table child_lock
      2   ( pk_col_1 number not null
      3     , seqno_1 number(1,0) not null
      4     , pk_col_2 number not null
      5     , seqno_2 number(1,0) not null
      6     , pk_col_3 number not null
      7     , seqno_3 number(1,0) not null
      8     , constraint chlk_pk primary key
      9          (pk_col_1, seqno_1, pk_col_2, seqno_2, pk_col_3, seqno_3)
     10     , constraint chlk_par_1_fk foreign key
     11          (pk_col_1, seqno_1) references child (pk_col, seqno)
     12     , constraint chlk_par_2_fk foreign key
     13          (pk_col_2, seqno_2) references child (pk_col, seqno)
     14     , constraint chlk_par_3_fk foreign key
     15          (pk_col_3, seqno_3) references child (pk_col, seqno)
     16    )
     17  /
    
    Table created.
    
    SQL> 
    SQL> insert all
      2      into parent values (pk_val, val_1)
      3      into child values (pk_val, 1, sysdate)
      4      into child values (pk_val, 2, sysdate+1)
      5      into child values (pk_val, 3, sysdate+2)
      6      into child_lock values (pk_val, 1, pk_val, 2, pk_val, 3)
      7  select 999 as pk_val
      8         , 'APPLE PIE' as val_1
      9  from dual
     10  /
    
    5 rows created.
    
    SQL> 
    SQL> insert into child values (999, 4, sysdate+4)
      2  /
    insert into child values (999, 4, sysdate+4)
    *
    ERROR at line 1:
    ORA-02290: check constraint (APC.CH_CK) violated 
    
    
    SQL> insert into child values (999, 3, sysdate+4)
      2  /
    insert into child values (999, 3, sysdate+4)
    *
    ERROR at line 1:
    ORA-00001: unique constraint (APC.CH_PK) violated 
    
    
    SQL> insert into child values (999, 2.5, sysdate+4)
      2  /
    insert into child values (999, 2.5, sysdate+4)
    *
    ERROR at line 1:
    ORA-00001: unique constraint (APC.CH_PK) violated 
    
    
    SQL> delete from child
      2  /
    delete from child
    *
    ERROR at line 1:
    ORA-02292: integrity constraint (APC.CHLK_PAR_1_FK) violated - child record found 
    
    
    SQL>
    

    我承认这个解决方案有点做作,也不灵活,但最初的要求也是如此。它也不是防弹的——从CHILD_LOCK中删除行,您可以删除一个或多个子记录

    您可以使用1:M关系正常创建表,然后在子表上有一个计数列,该列带有一个检查约束,用于确定父表中可以存在多少子表,以及父表ID+计数列上的唯一约束。e、 g:

    CREATE TABLE Parent (PID NUMBER PRIMARY KEY);
    
    CREATE TABLE Child (
        PID NUMBER NOT NULL,
        Count NUMBER(1) NOT NULL,
        CONSTRAINT count_check CHECK (Count BETWEEN 1 AND 5),
        CONSTRAINT parent_child_fk FOREIGN KEY (PID) REFERENCES Parent (PID),
        CONSTRAINT count_unique UNIQUE (PID, Count));
    

    唯一不能保证的是,每个父母至少有五个孩子;要解决这个问题,您可以按照WW的建议创建一个带有约束的物化视图,或者在应用程序中构建一些额外的内容(例如“错误”报告)。

    有一种替代解决方案,可以使用检查、外键和唯一性约束,强制每个父对象在没有物化视图的情况下正好有0个或n个子对象。为此,必须对子项进行编号,并添加一个包含下一个兄弟项编号的字段。这里是一个在PostgreSQL中工作的n=5示例,对于其他DBS,必须调整串行类型:

    最后一个(长)检查约束确保字段parent\u id、child\u nr和next\u sibling\u nr均为null或均不为null。唯一性约束和child_nr字段的检查确保父项最多有5个子项。对上的另一个检查约束和外键约束(父\u id,下一个\u同级\u nr)确保不少于5个子项

    使用命令插入具有自动生成的id 1的根之后

    insert into Tree (parent_id)
      values (null);
    
    可以始终以5个为一组添加子项:

    insert into Tree (parent_id, child_nr, next_sibling_nr)
      values (1, 1, 2),
             (1, 2, 3),
             (1, 3, 4),
             (1, 4, 5),
             (1, 5, 1);
    

    此解决方案源自我几周前提出的一个类似问题的答案。

    在插入父行之前,您需要插入孤立的子行。这是正确的,这就是插入应该在事务中的原因。使用触发器很难做到正确。您需要取出表锁,使其在表上的多个同时事务下正常工作。所有的事务都必须在后面等待,这样会执行得很糟糕。我只是看到其他人理解父母和孩子在不同的表中,而我认为他们在同一个表中。把我的答案改成两张表并不难。
    insert into Tree (parent_id)
      values (null);
    
    insert into Tree (parent_id, child_nr, next_sibling_nr)
      values (1, 1, 2),
             (1, 2, 3),
             (1, 3, 4),
             (1, 4, 5),
             (1, 5, 1);