我有一个MySQL表如下:
id, user, culprit, reason, status, ts_register, ts_update
我正在考虑将原因用作int字段,并且只存储用户可以选择的原因的id,并且管理员可以增加原因本身。
我的意思是增加的是管理员可以注册新的原因,例如目前我们有:
Flood, Racism, Hacks, Other
但是管理员可以添加一个新的理由:
Refund
现在我的问题是我想让我的用户选择多个原因,例如:
报告01包含Flood和Hack的原因。
我应该如何存储原因字段,以便在保持良好的表格格式的同时选择多个原因?
我是否应该继续将其存储为字符串并在搜索时将其转换为INT,或者有更好的表单来存储它?
更新根据Jonathan的回复:
SELECT mt.*, group_concat(r.reason separator ', ') AS reason
FROM MainTable AS mt
JOIN MainReason AS mr ON mt.id = mr.maintable_ID
JOIN Reasons AS r ON mr.reason = r.reason_id
GROUP BY mt.id
答案 0 :(得分:2)
规范化的解决方案是让第二个表包含一行,原因是:
CREATE TABLE MainReasons
(
MainTable_ID INTEGER NOT NULL REFERENCES MainTable(ID),
Reason INTEGER NOT NULL REFERENCES Reasons(ID),
PRIMARY KEY(MainTable_ID, Reason)
);
(假设您的主表名为MainTable,并且您有一个表定义称为原因的有效原因代码。)
来自评论:
[W]你能不能向我展示选择一些东西来检索报告的原因?我的意思是如果我简单地选择它SELECT * FROM MainTABLE我永远不会得到任何理由因为MainTable不知道它是对的吗?因为它只链接到MainReasons和Reasons表所以我需要做一些像SELECT * FROM MainTable LEFT JOIN MainReasons USING(MainTable_ID)之类的东西,但是我怎么会得到所有的原因,如果是倍数?
SELECT mt.*, r.reason
FROM MainTable AS mt
JOIN MainReason AS mr ON mt.id = mr.maintable_ID
JOIN Reasons AS r ON mr.reason = r.reason_id
这将按原因返回一行 - 因此它将为单个报告返回多行(记录在我称之为MainTable的内容中)。我从结果中省略了原因ID号 - 如果您愿意,可以包含它。
您可以向查询添加条件,向WHERE子句添加术语。如果要查看指定特定原因的报告:
SELECT mt.*
FROM MainTable AS mt
JOIN MainReason AS mr ON mt.id = mr.maintable_ID
JOIN Reasons AS r ON mr.reason = r.reason_id
WHERE r.reason = 'Flood'
(你不需要结果中的原因 - 你知道它是什么。)
如果你想查看“洪水”和“黑客”的报告,那么你可以写下:
SELECT mt.*
FROM MainTable AS mt
JOIN (SELECT f.MainTable_ID
FROM (SELECT MainTable_ID
FROM MainReason AS mr1
JOIN Reasons AS r1 ON mr1.reason = r1.reason_ID
WHERE r1.reason = 'Floods'
) AS f ON f.MainTable_ID = mt.MainTable_ID
JOIN (SELECT f.MainTable_ID
FROM (SELECT MainTable_ID
FROM MainReason AS mr2
JOIN Reasons AS r2 ON mr2.reason = r2.reason_ID
WHERE r1.reason = 'Hacks'
) AS h ON h.MainTable_ID = mt.MainTable_ID
答案 1 :(得分:1)
要做一对多的关系,我会把理性转移到它自己的表中,就像这样:
id, parent_id, reason
parent_id将返回当前表的id。
您可以将其存储为INT,但每次想要读取数据时都必须解析它。这种方式只需要再加入一次。