为了序言,我有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表时,我想检查它是否已经包含在其中一个中。或者换句话说,一个产品不能同时成为椅子和桌子。我该怎么做呢?
谢谢。
答案 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 ...