关系数据库设计问题 - 类别范围标记

时间:2017-08-10 11:27:39

标签: sql database database-design relational-database

我正在设计一个数据库,我有很多产品,每个产品属于一个且只有一个类别。

产品应该被标记,但只允许标记属于它们所属的类别。

这是我到目前为止所得到的:

database diagram

假设我有以下两类:

  • 智能
  • 笔记本

“智能手机”类别的标签:

  • 双SIM卡
  • GPS

“笔记本电脑”类别的标签:

  • 背光键盘
  • HDMI

此设计的问题在于数据库不会阻止产品被其他类别的标记标记:我的应用程序代码中的错误很容易导致笔记本电脑被标记为“双SIM卡”标记,这显然不是我想要的。

我想在数据库级别使用外键并且不使用触发器来防止这种情况。这有可能吗?

2 个答案:

答案 0 :(得分:3)

我能够在Oracle中执行以下操作。注意最后一次插入是如何失败的,我相信这就是你所追求的。

CREATE TABLE product (
    id            INTEGER NOT NULL,
    category_id   INTEGER NOT NULL,
    PRIMARY KEY ( id ),
    CONSTRAINT uq_prod_cat UNIQUE ( id,category_id )
);

INSERT INTO product (
    id,
    category_id
) VALUES (
    1,
    1
);

CREATE TABLE tags (
    id            INTEGER NOT NULL,
    category_id   INTEGER NOT NULL,
    PRIMARY KEY ( id ),
    CONSTRAINT uq_tag_cat UNIQUE ( id,category_id )
);

INSERT INTO tags (
    id,
    category_id
) VALUES (
    1,
    1
);

INSERT INTO tags (
    id,
    category_id
) VALUES (
    2,
    1
);

INSERT INTO tags (
    id,
    category_id
) VALUES (
    3,
    2
);

CREATE TABLE product_tags (
    id            INTEGER NOT NULL,
    product_id    INTEGER NOT NULL,
    category_id   INTEGER NOT NULL,
    tag_id        INTEGER NOT NULL,
    PRIMARY KEY ( id ),
    FOREIGN KEY ( product_id,category_id )
        REFERENCES product ( id,category_id ),
    FOREIGN KEY ( tag_id,category_id )
        REFERENCES tags ( id,category_id )
);

INSERT INTO product_tags (
    id,
    product_id,
    category_id,
    tag_id
) VALUES (
    1,
    1,
    1,
    1
);

1 row inserted.

INSERT INTO product_tags (
    id,
    product_id,
    category_id,
    tag_id
) VALUES (
    2,
    1,
    1,
    2
);

1 row inserted.

INSERT INTO product_tags (
    id,
    product_id,
    category_id,
    tag_id
) VALUES (
    3,
    1,
    1,
    3
);

Error starting at line : 35 in command -
INSERT INTO product_tags (id, product_id, category_id, tag_id) VALUES (3, 1, 1, 3)
Error report -
ORA-02291: integrity constraint (SYS_C008023) violated - parent key not found

答案 1 :(得分:0)

我的答案与Ashuntosh A的答案非常相似,不同之处在于我会创建一个单独的表来将标签与类别相关联,这样架构就可以将标签应用于更多的类别(例如平板电脑)和手机可能有DualSim):

diagram

--TSQL

create table ProductCategory
(
    id int primary key identity,
    name varchar(50) not null
)

create table ProductTag
(
    id int primary key identity,
    name varchar(50) not null
)

create table TagCategory
(
    tag_id int foreign key references ProductTag,
    category int foreign key references ProductCategory,
    primary key (tag_id, category)
)

create table Product
(
    id int primary key identity,
    type int foreign key references ProductCategory,
    unique (id, type)
)

create table TaggedProduct
(
    product int,
    tag int,
    type int,
    primary key (product, tag),
    foreign key (product, type) references Product (id, type),
    foreign key (tag, type) references TagCategory (tag_id, category)
)



insert ProductCategory
    select 'Laptop' union
    select 'Phone'

insert ProductTag
    select 'HDMI' union
    select 'Backlit Keyboard' union
    select 'Dual Sim' union
    select 'GPS'

insert TagCategory
    select 1, 1 union -- HDMI/LAPTOP
    select 2, 1 union -- Backlit/LAPTOP
    select 3, 2 union -- DualSim/PHONE
    select 4, 2 -- GPS/PHONE    

insert Product
    select 1 --a laptop

insert TaggedProduct
    select 1, 1, 1 --laptop has hdmi
    union select 1, 2, 1 --laptop has backlit keyboard

insert TaggedProduct select 1, 3, 1 
--fails because 'DualSim/Laptop' is not a valid category