Несколько данных хранятся в поле для лучшего управления? - PullRequest
0 голосов
/ 15 мая 2011

У меня есть таблица MySQL следующим образом:

id, user, culprit, reason, status, ts_register, ts_update

Я думал об использовании причины в качестве поля int и сохранении только идентификатора причины, который может быть выбран пользователем, и сама причина может быть увеличена администратором.

Что я имел в виду под увеличением, так это то, что администратор может зарегистрировать новую причину, например, в настоящее время мы имеем:

Flood, Racism, Hacks, Other

Но администратор может добавить новую причину, например:

Refund

Теперь моя проблема в том, что я хотел бы разрешить моим пользователям выбирать несколько причин, например:

В отчете 01 есть причины Flood и Hack.

Как мне сохранить поле причины, чтобы я мог выбрать несколько причин, поддерживая хороший формат таблицы?

Должен ли я просто пойти дальше и сохранить его как строку и привести его как INT, когда я ищу по нему, или есть лучшие формы для его хранения?

ОБНОВЛЕНИЕ На основании ответа Джонатана:

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 ]

2 голосов
/ 15 мая 2011

Нормализованное решение состоит в том, чтобы иметь вторую таблицу, содержащую по одной строке для каждой причины:

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 MainReason 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). Я пропустил идентификационный номер причины из результатов - вы можете включить его, если хотите.

Вы можете добавить критерии к запросу, добавив термины в предложение 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 голос
/ 15 мая 2011

Чтобы установить отношение один-ко-многим, я бы выделил причину в ее собственную таблицу, например:

id, parent_id, reason

parent_id вернул бы обратно в идентификатор вашей текущей таблицы.* Вы можете сохранить его как INT, но это будет постоянной болью - анализировать его каждый раз, когда вы захотите прочитать данные.Таким образом, потребуется еще одно соединение.

...