在数据库中用备注表示选择的理想方式
Ideal way to represent choices with remarks in database
我无法描述我的困境,但我说我必须 "grade" 一个等级为 A, B, C
的主题,我需要为每个主题提供评论。
每个主题分为 X 个类别,Y 个主题需要 "grade" 和备注。
| Topic 1 | A | B | C | Remarks |
|------------|---|---|---|---------|
| Subtopic A | | | | |
| Subtopic B | | | | |
|------------|---|---|---|---------|
| Topic 2 | A | B | C | Remarks |
|------------|---|---|---|---------|
| Subtopic A | | | | |
| Subtopic B | | | | |
| Subtopic C | | | | |
| Subtopic D | | | | |
范围:
- 所有子主题都是可选的
- 如果回答了子主题等级,则需要备注
限制:
- 我限于非BarracudaMySQL环境,我打算为每个remark分配2048字节
(SQL 伪代码而已,如有错误请勿介意)
方案A:
只需为每个主题做一个table,存储子主题名称、等级和备注,即
TABLE topic_1 (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
subtopic_a ENUM('A', 'B', 'C') NULL,
remarks_subtopic_a VARCHAR(2048) NULL,
subtopic_b ENUM('A', 'B', 'C') NULL,
remarks_subtopic_a VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
但这很糟糕,因为成绩没有在一个地方公布。
B计划:
为所有子主题创建 table,它们的名称是硬编码的,但引用了另一个 table 中声明的成绩。所有评论均按主题和资源限制分发给其他 table:
INSERT INTO grades (grade)
VALUES ("A"), ("B"), ("C");
TABLE topics (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
topic_1_subtopic_a INT UNSIGNED NULL,
FOREIGN KEY (topic_1_subtopic_a)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
topic_1_subtopic_b INT UNSIGNED NULL,
FOREIGN KEY (topic_1_subtopic_a)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
topic_2_subtopic_a INT UNSIGNED NULL,
FOREIGN KEY (topic_1_subtopic_a)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
...
) ENGINE=INNODB DEFAULT CHARSET=utf8;
TABLE remarks_topic_1 (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
subtopic_a VARCHAR(2048) NULL,
subtopic_b VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
TABLE remarks_topic_2 (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
subtopic_a VARCHAR(2048) NULL,
subtopic_b VARCHAR(2048) NULL
subtopic_c VARCHAR(2048) NULL,
subtopic_d VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
方案C:
由于我们有一个子主题的模式具有以下属性:
- 超主题
- 等级
- 备注
为此制作一个table,其中contract的主题数量及其各自的子主题只有"assembled"并且在前端已知;在后端,它们都只被视为 subtopic
数据库对象:
INSERT INTO grades (grade)
VALUES ("A"), ("B"), ("C");
TABLE subtopics (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
topic VARCHAR(100) NULL,
subtopic INT UNSIGNED NULL,
FOREIGN KEY (grades)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
remarks VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
优点:
- 广义模式
grades
在数据库中定义
- 给定
remarks
不难存储一个完成subtopic
缺点:
- 前端只知道contract/business逻辑
- 主题和子主题未硬编码
C 计划是一个好的开始方式吗?或者有更好的方法来处理这个问题吗?
是的,C 计划是更好的设计,因为它更加规范化和可扩展。这是对 RDBMS 建模的推荐方法。您还可以将 "Topic" 列外部化到单独的 table 中,或者可以在同一 table 中建立父子关系,以便您可以更轻松地管理主题。否则主题将在所有子主题中重复,如果将来有任何更改,您可能必须更新所有行。
提到的所有其他方法都存在一些可扩展性和可维护性问题。
我无法描述我的困境,但我说我必须 "grade" 一个等级为 A, B, C
的主题,我需要为每个主题提供评论。
每个主题分为 X 个类别,Y 个主题需要 "grade" 和备注。
| Topic 1 | A | B | C | Remarks |
|------------|---|---|---|---------|
| Subtopic A | | | | |
| Subtopic B | | | | |
|------------|---|---|---|---------|
| Topic 2 | A | B | C | Remarks |
|------------|---|---|---|---------|
| Subtopic A | | | | |
| Subtopic B | | | | |
| Subtopic C | | | | |
| Subtopic D | | | | |
范围:
- 所有子主题都是可选的
- 如果回答了子主题等级,则需要备注
限制:
- 我限于非BarracudaMySQL环境,我打算为每个remark分配2048字节
(SQL 伪代码而已,如有错误请勿介意)
方案A:
只需为每个主题做一个table,存储子主题名称、等级和备注,即
TABLE topic_1 (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
subtopic_a ENUM('A', 'B', 'C') NULL,
remarks_subtopic_a VARCHAR(2048) NULL,
subtopic_b ENUM('A', 'B', 'C') NULL,
remarks_subtopic_a VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
但这很糟糕,因为成绩没有在一个地方公布。
B计划:
为所有子主题创建 table,它们的名称是硬编码的,但引用了另一个 table 中声明的成绩。所有评论均按主题和资源限制分发给其他 table:
INSERT INTO grades (grade)
VALUES ("A"), ("B"), ("C");
TABLE topics (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
topic_1_subtopic_a INT UNSIGNED NULL,
FOREIGN KEY (topic_1_subtopic_a)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
topic_1_subtopic_b INT UNSIGNED NULL,
FOREIGN KEY (topic_1_subtopic_a)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
topic_2_subtopic_a INT UNSIGNED NULL,
FOREIGN KEY (topic_1_subtopic_a)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
...
) ENGINE=INNODB DEFAULT CHARSET=utf8;
TABLE remarks_topic_1 (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
subtopic_a VARCHAR(2048) NULL,
subtopic_b VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
TABLE remarks_topic_2 (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
subtopic_a VARCHAR(2048) NULL,
subtopic_b VARCHAR(2048) NULL
subtopic_c VARCHAR(2048) NULL,
subtopic_d VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
方案C:
由于我们有一个子主题的模式具有以下属性:
- 超主题
- 等级
- 备注
为此制作一个table,其中contract的主题数量及其各自的子主题只有"assembled"并且在前端已知;在后端,它们都只被视为 subtopic
数据库对象:
INSERT INTO grades (grade)
VALUES ("A"), ("B"), ("C");
TABLE subtopics (
id AUTO_INCREMENT UNIQUE PRIMARY KEY,
topic VARCHAR(100) NULL,
subtopic INT UNSIGNED NULL,
FOREIGN KEY (grades)
REFERENCES grades(id)
ON DELETE CASCADE
ON UPDATE CASCADE,
remarks VARCHAR(2048) NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8;
优点:
- 广义模式
grades
在数据库中定义- 给定
remarks
不难存储一个完成
subtopic
缺点:
- 前端只知道contract/business逻辑
- 主题和子主题未硬编码
C 计划是一个好的开始方式吗?或者有更好的方法来处理这个问题吗?
是的,C 计划是更好的设计,因为它更加规范化和可扩展。这是对 RDBMS 建模的推荐方法。您还可以将 "Topic" 列外部化到单独的 table 中,或者可以在同一 table 中建立父子关系,以便您可以更轻松地管理主题。否则主题将在所有子主题中重复,如果将来有任何更改,您可能必须更新所有行。
提到的所有其他方法都存在一些可扩展性和可维护性问题。