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

What's the proper way to store this data in a MySQL schema?

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

它是 table 中的一行。

但是我想让我的用户完全自定义此信息,以防他们认为有什么不正确的地方,或者如果他们只是想以某种方式修改数据的显示方式.我不在乎为什么,我只是想给我的用户一个选择,让他们做他们想做的事。

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

假设用户 #2 想将 DVD 改为数字拷贝。

假设用户 #3 想要将他们的标题更改为 "Twelve Monkeys",因为它是备用标题。

等等

我的问题是,如何在不修改原始数据的情况下,仅存储该用户名对那个字段的更改?在一个单独的相同 table 中,除了 one 字段外,所有字段都具有完全相同的数据?或者我可以只将一个更改(例如标题)存储在某个地方,然后参考 movie 数据以获取其余信息吗?

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

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

我的第二个想法是 customizations table

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

然后,当用户查询系统时,在 customizations table 中查找他们的用户 ID 和 column_name 以找到替代显示值。

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

不是每部电影一行,而是使用 attribute-value table。然后向其中添加一个额外的字段来指定用户,对于原始默认值,这将是 0。所以 table 看起来像:

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 而不是字符串作为属性名称,并使用单独的 table 将属性名称映射到 ID。

我建议没有'proper'方法。但你可能会喜欢这个...

  • 您的 Movie table 保持原样。 (我假设有一个 id。)
  • 另一个 table、UserMovie 具有相同的列,除了:
    • id以外的所有列都是NULL
    • 它还有另一列:user NOT NULL
    • PRIMARY KEY(id, user)

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

COALESCE 静静地拍照 u.xxx if NOT NULLm.xxx.

这种设计的优点是非常紧凑。 (NULLs几乎没有space。)

如果用户更改 "title" 两次,则仅保留最后一个版本。

给"revert"标题:

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

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

好的设计并不适用于所有情况。然而,有一个针对特定情况的完美设计。

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

根据你的问题,如果一部电影从不改变它的属性,那么单行 table 是完美的:

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

你可能需要一个外国的 table movie_format

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

以上设计搜索速度非常快

现在您想保存任何更改或替代信息,但不确定它们是什么。在这种情况下,meta table 更 suitable。 Meta table 如果你只需要根据主键(电影)显示而不用于搜索,通常是完美的:

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 作为枚举,这样您就不必担心新的查找 table