8

У меня есть movie в базе данных MySQL. movie содержит атрибуты данных, которые никогда не изменятся, такие как:Каков правильный способ хранения этих данных в схеме MySQL?

  • Штрих-код: 025192018626
  • Формат: DVD
  • Продолжительность: 121 мин.
  • Диски: 1
  • Название: 12 Monkeys
  • Год выпуска: 1995

Это одна строка в таблице.

Но Я хочу дать полную информацию о моей пользователе в отношении этой информации в случае, если что-то не соответствует им или если они просто хотят изменить способ отображения данных каким-либо образом. Меня не волнует, почему, я просто хочу дать своим пользователям возможность делать то, что они хотят.

Предположим, что пользователь # 1 хочет изменить заголовок, чтобы он был «12 обезьян (полка 1)», и это все, что они меняют.

И, скажем, пользователь # 2 хочет вместо этого заменить DVD на цифровую копию.

И, скажем, пользователь №3 хочет изменить заголовок, чтобы они были «Двенадцать обезьян», потому что это альтернативный заголовок.

т.д.

Мой вопрос, как я могу хранить только что одно изменение в этом одно поле только для этого пользователя, не изменяя исходные данные? В отдельной идентичной таблице со всеми полями указаны одни и те же данные, за исключением того, что один поле? Или я могу просто сохранить одно единственное изменение (например, название) и вернуться к данным movie для остальных?

Каков правильный способ его разработки, особенно если у меня есть 1000 пользователей, которые вносят изменения в пользовательские данные в основном на одно или два поля?

+0

Что относительно фильмов, имеющих несколько названий? Это не просто «Двенадцать обезьян» против «12 обезьян», но это также может быть «L'armée des 12 singes» или любое другое название на [странице IMDB] (http://www.imdb.com/title/tt0114746/releaseinfo). Это отношение «один ко многим» может быть важным для некоторых, а может и нет. Также вы перекрестно связываете вещи, например, если они купили его как комбинированный пакет DVD/Blu-Ray? – tadman

+0

Учитывая, что вы знаете столбцы, которые вы переопределяете, нет необходимости использовать конструкции EAV (атрибутные значения столбцов), которые предлагаются в некоторых ответах. Даже если пользователи могут изобретать свои собственные столбцы, прежде чем использовать EAV, вы должны продемонстрировать, что он превосходит DML/DDL с простыми таблицами. – philipxy

ответ

12

Вместо одной строки для каждого фильма используйте таблицу значений атрибута. Затем добавьте к нему дополнительное поле, которое указывает пользователя, который будет 0 для первоначального значения по умолчанию.Таким образом, таблица выглядит следующим образом:

MovieID UserID Attribute Value 
1  0  Title  12 Monkeys 
1  0  Format  DVD 
1  1  Title  Twelve Monkeys 

Тогда запрос, чтобы получить титул будет выглядеть так:

SELECT MovieID, IFNULL(my.Value, default.Value) AS title 
FROM movies AS default 
LEFT JOIN movies AS my ON default.MovieID = my.MovieID AND my.Attribute = 'Title' AND my.userID = @user 
WHERE default.UserID = 0 AND default.Attribute = 'Title' 

Некоторые разработчики баз данных также хотели бы использовать AttributeID вместо строки в качестве имени атрибута, и отдельную таблицу, которая сопоставляет имена атрибутов идентификаторам.

+0

Любой потенциал роста до нормализации с помощью атрибута AttributeID? Похоже на дополнительное ненужное соединение? –

+1

Согласен, вот почему я этого не делаю. Некоторые люди просто педантичны по поводу нормализации. – Barmar

+1

Возможным преимуществом является интернационализация. Вы можете легко заменить имена атрибутов на внешние значения. – Barmar

3

Моя первая мысль: зачем вам это нужно?

Моя вторая мысль иметь customizations стол что-то вроде

+--------+---------+-------------+------------+ 
| userid | barcode | column_name | custom_val | 
+--------+---------+-------------+------------+ 

тогда, когда пользователь запрашивает систему, искать их идентификатор пользователя и column_name в customizations таблице, чтобы найти альтернативное значение дисплея.

Это позволит пользователю заменить одно значение в одной строке. Заменить одно значение во всех строках, где оно существует, было бы гораздо более сложным предложением.

+0

Я согласен с подходом. Недостатком этого является то, что все значения custom_val теперь должны быть сохранены как строки, хотя некоторые из них фактически являются целыми числами и т. Д. – Galz

+0

У вас могут быть столбцы custom_val_str', 'custom_val_int' и т. Д. – Barmar

+0

«Почему» часть связана с внедрением пользовательской методики коррекции данных, над которой я работаю. В конце концов я буду разрабатывать программу, которая может видеть, какие пользователи меняют какие данные (и соотношение изменений и т. Д.), И внедрять некоторые алгоритмы, которые автоматически корректируют или заполняют данные. Это особенно важно для иностранных фильмов, неясных фильмов и т. Д., В которых нет полных и/или правильных данных. Это также выходит за рамки фильмов ... но фильмы просто используются в качестве примера здесь. –

7

Я предлагаю, что нет «правильного» способа. Но вам может понравиться это ...

  • Ваш Movie стол остается как есть. (Я предполагаю, что есть id.)
  • Другая таблица, UserMovie с теми же колоннами, за исключением:
    • Все столбцы, кроме id являются NULL
    • Он имеет еще один столбец: user NOT NULL
    • PRIMARY KEY(id, user)

Когда пользователь что-то изменяет, используйте INSERT INTO UserMovie .. ON DUPLICATE KEY UPDATE .. изменить любое поле (и), которое он хочет установить. Обратите внимание, что IODKU будет INSERT новой строки, если она не существует, или UPDATE существующей строки (поскольку пользователь модифицирует другой столбец). Например, чтобы переопределить только "название" для ид = $ ID,

INSERT INTO UserMovie 
    (id, title) 
    VALUES 
    ($id, '$title') 
ON DUPLICATE KEY UPDATE 
    title = '$title'; 

Когда пользователь хочет увидеть, что у него есть,

SELECT coalesce(u.title, m.title) AS title, 
     coalesce(u.format, m.format) AS format, 
     coalesce... 
    FROM Movie AS m 
    LEFT JOIN UserMovie AS u 
      ON u.id = m.id 
      AND u.user = $user 
    WHERE m.id = $id; 

В COALESCE тихо Pics либо u.xxx если NOT NULL, или m.xxx.

Эта конструкция имеет то преимущество, что она очень компактна. (NULLs почти не занимают места.)

Если пользователь дважды меняет «заголовок», сохраняется только последняя версия.

Чтобы «вернуть» название:

UPDATE UserMovie SET title = NULL 
    WHERE id = $id 
     AND user = $user; 

(Конечно, это может оставить ряд всех NULLs, но остальная часть кода все еще работает.)

+0

Мне нравится эта идея, проблема заключается в том, что я должен иметь две повторяющиеся таблицы по существу. Они должны иметь соответствующие имена и типы столбцов, поэтому, если я хочу что-то изменить (например, 'desc - VARCHAR (255)' to 'description - TEXT'), то я должен помнить, что нужно сделать это в двух местах, и нет чтобы связать эти два столбца вместе, чтобы убедиться, что это сделано правильно. Но я тоже планирую идти по этому маршруту или что-то очень похожее. –

+0

Кроме того, вам нужно сделать это в 'SELECT' time; бизнес-логика не позволяет объединить их в одну таблицу. –

+0

'VARCHAR' и' TEXT' достаточно совместимы, поэтому я не вижу в этом проблемы. То есть 'COALESCE (u.varchar_col, m.text_col)' должен работать. Или мне не хватает вашей заботы? –

2

Хороший дизайн не является совершенным для всех ситуаций. Однако есть идеальный дизайн для ситуации.

Задайте себе вопрос: 1) какова цель этого проекта и 2) как вы собираетесь извлекать данные из проекта.

По вашему вопросу, если фильм не изменяет его атрибуты, плоская таблица однорядная идеально:

table: movie 
id | barcode  | format_id | runtime | disc | year_made | title 
---+--------------+-----------+---------+------+-----------+----------- 
1 | 025192018626 | 1   | 121  | 1 | 1995  | 12 Monkeys 

И вам может понадобиться внешняя таблица movie_format

table: movie_format 
id | format 
---+------- 
1 | DVD 

Над дизайном очень быстро подходит для поиска.

Теперь вы хотите сохранить все изменения или другую информацию, но не уверены в том, что это такое. В этом случае мета-таблица более подходит. Meta таблица, как правило, идеально подходит, если вам нужно только для отображения в соответствии с первичным ключом (фильм) и не используется для поиска:

table: movie_meta 
id | movie_id | user_id | created    | meta  | info 
---+----------+---------+---------------------+-----------+--------- 
1 | 1  | 123  | 2016-01-28 11:22:33 | format_id | 2 
2 | 1  | 456  | 2016-01-28 11:55:33 | disc  | 3 
5 | 1  | 666  | 2016-07-14 12:58:55 | title  | 十二头傻猴子 

Вы можете сделать movie_meta.meta как перечисление, так что вам не нужно беспокоиться о новой таблице поиска

Смежные вопросы