可能由其他相同实体组成的实体的数据库设计
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 值存储在列中。
我有一些体育设施,里面有可以踢 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 值存储在列中。