可能由其他相同实体组成的实体的数据库设计

Database design for an entity that might comprise from other same entities

我有一些体育设施,里面有可以踢 5x5 足球的场地。我正在尝试为他们制作一个简单的预订系统。 我的问题是,一些字段合并并形成更大的字段,设施的管理人员希望将它们视为自己的实体(有道理,如果他们这样预订,为什么不这样做)。

举个实际例子吧。 我们有设施 FA。他们有 3 个 5x5 的字段,一个接一个,让我们调用 sa, sb, sc,它们中的任何两个可以组合成一个 7x7 的字段,我们称之为 dd,所有三个组成一个 10x10 的字段,让我们调用它 te。 其他设施也会发生这种情况,但这是更极端的情况。

我一直在思考如何在预订和处理时为字段建模table,但我不确定。

我的一个解决方案是为字段设置 table

CREATE TABLE IF NOT EXISTS field (
    id              SMALLINT(5) UNSIGNED    NOT NULL AUTO_INCREMENT,
    arena_id        SMALLINT(4) UNSIGNED    NOT NULL,
    internal_id     TINYINT(3) UNSIGNED     NOT NULL,
    is_composite    BOOLEAN                 NOT NULL DEFAULT FALSE,

    PRIMARY KEY (id),
    UNIQUE (arena_id, internal_id),

    CONSTRAINT fk_field_arena_id FOREIGN KEY (arena_id) REFERENCES arena(id) ON UPDATE CASCADE ON DELETE CASCADE
)
;

并且他们与另一个人存在一对一或零关系 table

CREATE TABLE IF NOT EXISTS field_component (
    field_id        SMALLINT(5) UNSIGNED    NOT NULL,
    component       SMALLINT(5) UNSIGNED    NOT NULL,

    PRIMARY KEY (field_id, component),

    CONSTRAINT fk_field_component_field_id FOREIGN KEY (field_id) REFERENCES field(id) ON UPDATE CASCADE ON DELETE CASCADE,
        CONSTRAINT fk_field_component_field_id2 FOREIGN KEY (component) REFERENCES field(id) ON UPDATE CASCADE ON DELETE CASCADE

)
;

将包含包含组件字段的字段的条目。只有当 field table 中的标志 is_composite 为真时,条目才会存在于此。

我认为一个更简单的解决方案是更手动的,而不是有第二个 table 和标志,只有一个字符串列,我把字段的 id 放在作为逗号分隔列表的复合字段。

在一个单独的说明中,我正在考虑将标志移动到第三个 table 称为 field_info 我可能与该字段有一对一的关系并将包含有关每个字段的信息场地。即地面的大小,material,如果它是合成的或不是,关于它的注释等

欢迎任何想法建议、批评、替代方案。

我会考虑以下内容,确保在复合 table field_component 中 child 和复合领域至少相同。请注意,不强制执行 InnoDB 检查约束。

第 1 点:is_composite 下面的 field_component 隐式指向真正复合的东西的质量没有强制执行。它可能有更多的合成(意味着更多 tables)。

第 2 点:在现阶段或以后,不应将数据类型过度设计为小型和微型 INT。特别是 mysql.

的新手

第 3 点:FK 关系倾向于在 child table 中不存在时自动为您创建 KEYS。我们在 field_component 中明确拥有的唯一键实际上有两个目的。它强制执行 non-dupes,并且它用作索引,用于生成 FK auto-gen 的位置。另一个是自动生成的,如 show create table 中所示。因此,我们的 UNIQUE KEY 有几个用途。

CREATE TABLE IF NOT EXISTS field (
    id              SMALLINT(5) UNSIGNED    NOT NULL AUTO_INCREMENT,
    arena_id        SMALLINT(4) UNSIGNED    NOT NULL,
    internal_id     TINYINT(3) UNSIGNED     NOT NULL,
    is_composite    BOOLEAN                 NOT NULL DEFAULT FALSE,

    PRIMARY KEY (id),
    UNIQUE (arena_id, internal_id),

    CONSTRAINT fk_field_arena_id FOREIGN KEY (arena_id) REFERENCES arena(id) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS field_component (
    field_id        SMALLINT(5) UNSIGNED    NOT NULL,
    component       SMALLINT(5) UNSIGNED    NOT NULL,

    PRIMARY KEY (field_id, component),

    CONSTRAINT fk_field_component_field_id FOREIGN KEY (field_id) REFERENCES field(id) ON UPDATE CASCADE ON DELETE CASCADE,
        CONSTRAINT fk_field_component_field_id2 FOREIGN KEY (component) REFERENCES field(id) ON UPDATE CASCADE ON DELETE CASCADE

);

TweakA:

CREATE SCHEMA TweakA;
USE TweakA;

-- drop table arena
CREATE TABLE IF NOT EXISTS arena
(   id INT PRIMARY KEY,
    aName varchar(200) NOT NULL
);

-- drop table field
CREATE TABLE IF NOT EXISTS field
(   id INT AUTO_INCREMENT PRIMARY KEY,
    arena_id INT NOT NULL, -- like the Arena #
    internal_id INT NOT NULL, -- 1, 2, 3 for the field #
    is_composite BOOLEAN NOT NULL DEFAULT FALSE,
    friendly_name VARCHAR(100) NOT NULL,
    UNIQUE KEY (arena_id, internal_id),
    CONSTRAINT fk_field_arena_id FOREIGN KEY (arena_id) REFERENCES arena(id) ON UPDATE CASCADE ON DELETE CASCADE
);

-- drop table field_component
CREATE TABLE IF NOT EXISTS field_component
(   id INT AUTO_INCREMENT PRIMARY KEY,
    arena_id INT NOT NULL,
    child_internal_id INT NOT NULL,
    composite_internal_id INT NOT NULL,

    -- The following UK will pick up part of what I will explain in the Narrative
    UNIQUE KEY `unq_arena_comp_child` (arena_id,child_internal_id,composite_internal_id),

    CONSTRAINT fk_field_child_field_id FOREIGN KEY (arena_id,child_internal_id) 
        REFERENCES field(arena_id, internal_id) ON UPDATE CASCADE ON DELETE CASCADE,
    CONSTRAINT fk_field_composite_field_id FOREIGN KEY (arena_id,composite_internal_id) 
        REFERENCES field(arena_id, internal_id) ON UPDATE CASCADE ON DELETE CASCADE

    -- note that InnoDB check constraints are not effective
);

-- Note, look at output from the following
-- show create table field_component; -- this shows the auto-gen of 1 key due to FK
-- 

-- The following block is a Helper block during testing
-- Truncate in reverse order:
-- TRUNCATE TABLE field_component;
-- TRUNCATE TABLE field;
-- TRUNCATE TABLE arena;

-- test data load:
INSERT arena(id,aName) VALUES (1,'Boston Arena, North Shore');

INSERT field(arena_id,internal_id,is_composite,friendly_name) VALUES
(1,1,FALSE,'sa'),
(1,2,FALSE,'sb'),
(1,3,FALSE,'sc'),
(1,4,TRUE,'dab'),
(1,5,TRUE,'dac'),
(1,6,TRUE,'dbc'),
(1,7,TRUE,'abc');

INSERT field_component(arena_id,child_internal_id,composite_internal_id) VALUES
(1,1,4),
(1,2,4),

(1,1,5),
(1,3,5),

(1,2,6),
(1,3,6),

(1,1,7),
(1,2,7),
(1,3,7); -- SUCCESS

INSERT field_component(arena_id,child_internal_id,composite_internal_id) VALUES
(2,2,4); -- will fail, as expected

INSERT field_component(arena_id,child_internal_id,composite_internal_id) VALUES
(1,72,4); -- will fail, as expected

INSERT field_component(arena_id,child_internal_id,composite_internal_id) VALUES
(1,1,444); -- will fail, as expected

show create table field_component;
-- the above will exhibit the AUTO_INCREMENT gap anomoly due to the above
-- expected failed inserts, setting AI=13 or so

DROP SCHEMA TweakA;

我写了一个 的答案,有点复杂。您可以根据您正在寻找的数据库执行级别走这条路。

另见 MySQL Using FOREIGN KEY Constraints 关于 auto-gen 的 KEYS 由于第 3 点中提到的 FK 关系。

因此,随着您通过执法工作,这个答案可能会不断增长。或者做客户端。如果是我,我会做DB Enforcement。

无论如何,如评论中所述,不要将 CSV 值存储在列中。