将此数据存储在MySQL模式中的正确方法是什么?

时间:2016-07-05 21:17:07

标签: mysql database-design relational-database schema database-schema

我在MySQL数据库中有一个moviemovie包含永不改变的数据属性,例如:

  • 条形码:025192018626
  • 格式:DVD
  • 运行时间:121分钟
  • 光盘:1
  • 标题:12只猴子
  • 年份:1995

它是表格中的一行。

但是我想让我的用户对这些信息进行完全自定义,以防万一根据它们不正确,或者他们只是想以某种方式修改数据的显示方式。我不在乎为什么,我只是想让我的用户选择他们想要的东西。

假设用户#1想要将他们的标题更改为“12 Monkeys(Shelf 1)”,这就是他们所有的变化。

让我们说用户#2想要将DVD改为数字拷贝。

让我们说用户#3想要将他们的标题更改为“十二只猴子”,因为它是替代标题。

我的问题是,如何在不修改原始数据的情况下,只将 存储一个字段更改为该用户名?在一个单独的相同表中,除了一个字段外,所有字段都是完全相同的数据?或者我可以在某处存储一个单独的更改(例如标题)并返回其余的movie数据?

设计这个的正确方法是什么,特别是如果我有1000个用户主要在一两个字段上进行自定义数据修改?

4 个答案:

答案 0 :(得分:13)

使用属性值表而不是每部电影的单行。然后为此添加一个指定用户的附加字段,原始默认值为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而不是字符串作为属性名称,以及使用单独的表将属性名称映射到ID。

答案 1 :(得分:7)

我建议没有适当的'办法。但你可能会喜欢这个......

  • 您的Movie表保持不变。 (我假设有一个id。)
  • 另一个表UserMovie具有相同的列,但以下情况除外:
    • id以外的所有列均为NULL
    • 它有另一栏:user NOT NULL
    • PRIMARY KEY(id, user)

当用户修改某些内容时,请使用INSERT INTO UserMovie .. ON DUPLICATE KEY UPDATE ..更改他想要设置的任何字段。请注意,如果不存在,IODKU将INSERT新行,或者UPDATE现有行(因为用户正在修改另一列)。例如,要仅覆盖"标题"对于id = $ 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;

如果COALESCEu.xxxNOT NULLm.xxx静静地拍照。

这种设计具有非常紧凑的优点。 (NULLs几乎没有空间。)

如果用户更改"标题"两次,只保留最后一个版本。

To" revert"标题:

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

(当然,这可能会留下所有NULLs的一行,但其余的代码仍然有用。)

答案 2 :(得分:3)

我的第一个想法是,你为什么要这样做?

我的第二个想法是让customizations表格像

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

然后,当用户查询系统时,在customizations表中查找其用户标识和column_name以查找替代显示值。

这将允许用户替换一行中的一个值。要在存在它的所有行中替换一个值将是一个更加困难的命题。

答案 3 :(得分:2)

好的设计并非适用于所有情况。然而,对于某种情况,有一个完美的设计。

再问自己:1)这个设计的目的是什么,2)你将如何从设计中检索数据。

根据你的问题,如果电影永远不会改变它的属性,那么平面的单行表是完美的:

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

你可能需要一个外表table_format

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

以上设计非常快速搜索。

现在您要保存所有更改或替代信息,但不确定它们是什么。在这种情况下,元表更合适。如果您只需要根据主键(电影)进行显示而不用于搜索,则元表通常是完美的:

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设为enum,这样您就不必担心新的查找表