检查父表的记录的ID是否仅包含在其中一个子表中

时间:2018-03-28 17:05:56

标签: sql oracle

为了序言,我有3个表,有表

Product
- id
- name
- availability

然后是2个子表:

Tables
- id
- product_id (foreign key to product(id))
- size

Chairs
- id
- product_id (foreign key to product(id))
- color

我想要做的是每当我将新记录插入chair / tables表时,我想检查它是否已经包含在其中一个中。或者换句话说,一个产品不能同时成为椅子和桌子。我该怎么做呢?

谢谢。

1 个答案:

答案 0 :(得分:1)

您可以为此使用CHECK约束,它与其他一些约束相结合,可以为您提供所需的行为。检查约束有一些限制,其中之一是:

  

检查约束的条件可以指代中的任何列   表,但它不能引用其他表的列。

(参见documentation

在以下示例中,ID列" chairs.id"和" tables.id"已被转移到"产品" table,包含CHECK约束。 UNIQUE约束强制实现一对一的关系(对于每个REFERENCED ID仅允许一个值)。 DDL代码看起来有点忙,但这里有:

<强>表格

create table products (
  id number generated always as identity primary key
, name varchar2(128)
, availability varchar2(32)
);

-- product_id removed
create table tables (
  id number primary key
, size_ number
) ;

-- product_id removed
create table chairs (
  id number primary key
, color varchar2(32)
);

其他列和约束

alter table products
add (
  table_id number unique
, chair_id number unique
, check (
    ( table_id is not null and chair_id is null )
    or
    ( table_id is null and chair_id is not null )
  )
);

alter table tables
add constraint fkey_table
foreign key ( id ) references products ( table_id ) ;

alter table chairs
add constraint fkey_chairs
foreign key ( id ) references products ( chair_id ) ;

测试

-- {1} Add a chair: the chair_id must exist in PRODUCTS.
insert into chairs ( id, color ) values ( 1000, 'maroon' ) ;
-- ORA-02291: integrity constraint ... violated - parent key not found

-- Each chair needs an entry in PRODUCTS first:
insert into products ( name, availability, chair_id ) 
  values ( 'this is a chair', 'in stock', 1000 ) ;
insert into chairs ( id, color ) values ( 1000, 'maroon' ) ;
-- okay

-- {2} We cannot add another chair that has the same chair_id. Good.
insert into products ( chair_id ) values ( 1000 ) ;
-- ORA-00001: unique constraint ... violated


-- {3} Add a table.
insert into products ( name, availability, table_id ) 
  values ( 'this is a table', 'unavailable', 1000 ) ; 
-- okay
insert into tables ( id, size_ ) values ( 1000, 60 ) ;

-- {4} Is it possible to add another table, with the same table_id? No. Good.
insert into tables ( id, size_ ) values ( 1000, 60 ) ;
-- ORA-00001: unique constraint ... violated
insert into products ( name, availability, table_id ) 
  values ('this is a table', 'unavailable', 1000 ) ; 
-- ORA-00001: unique constraint ... violated

-- {5} We cannot add something that is a chair _and_ a table (at the same time).
insert into products ( name, availability, table_id, chair_id )
  values ( 'hybrid', 'awaiting delivery', 2000, 2000 ) ;
-- ORA-02290: check constraint ... violated

<强>结果集

SQL> select * from products;
ID  NAME             AVAILABILITY  TABLE_ID  CHAIR_ID  
21  this is a chair  in stock      NULL      1000      
23  this is a table  unavailable   1000      NULL 

注意:产品ID(不是table_id或chair_id)&#34;标识&#34;特定的桌子/椅子。 TABLE_ID和CHAIR_ID列中的值仅用于&#34; link&#34;到子表中的(唯一)ID。

替代方案:对象关系方法。

此解决方案可能更适合解决问题。在这里,我们首先创建一个超类型(product_t),然后分别创建2个子类型(chair_t和table_t)。这允许我们使用product_t创建表PRODUCTS_,以存储我们需要的数据。

类型和表格

create or replace type product_t as object (
  name varchar2(64)
, availability varchar2(64)
)
not final;
/

create or replace type chair_t under product_t (
  color varchar2(64)
)
/

create or replace type table_t under product_t (
  size_ number
)
/

create table products_ (
  id number generated always as identity primary key
, product product_t
);

<强>测试

-- "standard" INSERTs
begin
  insert into products_ ( product ) 
    values ( chair_t( 'this is a chair', 'in stock', 'maroon' ) );
  insert into products_ ( product )
    values ( table_t( 'this is a table', 'not available', 60 ) ); 
end;
/

-- unknown types cannot be inserted
insert into products_ ( product )
    values ( unknown_t( 'type unknown!', 'not available', 999 ) ); 
-- ORA-00904: "UNKNOWN_T": invalid identifier

insert into products_ ( product )
    values ( product_t( 'supertype', 'not available', 999 ) ); 
-- ORA-02315: incorrect number of arguments for default constructor

-- object of SUPERtype can be inserted
insert into products_ ( product )
    values ( product_t( 'supertype', 'not available' ) ); 
-- 1 row inserted.

<强>查询

select 
  id
, treat( product as table_t ).name   as name_of_table
, treat( product as chair_t ).name   as name_of_chair
, case
    when treat( product as table_t ) is not null
      then 'TABLE_T'
    when treat( product as chair_t ) is not null
      then 'CHAIR_T'
    when treat( product as product_t ) is not null
      then 'PRODUCT_T'
    else
      'TYPE unknown :-|'
  end which_type_is_it
from products_ ;

-- result

ID  NAME_OF_TABLE    NAME_OF_CHAIR    WHICH_TYPE_IS_IT  
1   NULL             this is a chair  CHAIR_T           
2   this is a table  NULL             TABLE_T           
3   NULL             NULL             PRODUCT_T        -- neither a chair nor a table ...