多个数据存储在一个字段中以便更好地管理?

时间:2011-05-15 01:36:00

标签: mysql sql database-design data-modeling one-to-many

我有一个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

2 个答案:

答案 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,但每次想要读取数据时都必须解析它。这种方式只需要再加入一次。