MySQL数据库设计用于图像选项关系

时间:2012-07-01 04:28:15

标签: php mysql sql database-design relationship

我有两张表,图片 image_data ,这是我的image_data表的一个示例。

image_id | slide_id | language_id  | type   |
101      | 1        | 1            | CQ     |
101      | 2        | NULL         | NULL   |
56       | 5        | 1            | TN     |
56       | NULL     | 2            | NULL   |

所以基本上,每个图像都有不同的选项,我想知道实现这个的最好方法..因为我有一种感觉,我这样做是错误的。

有了这个,我可以运行一个查询来使用GROUP_CONCAT()将多行中的值转换为单个连接字符串。

image_id | slide_id | language_id  | type   |
101      | 1,2      | 1            | CQ     |
56       | 5        | 1,2          | TN     |

哪个好,但我现在这样做的问题是......看起来用我的后端系统更新行真的很难。

enter image description here

因此,根据我的查询,我可以根据数据库确定要检查哪些数据库,因为我将它连接在一起,因为我将它连接起来。但是现在它就像..当我点击“保存”并更新行时,我会更新哪一行?相同的图像ID可以有多于一行,所以如何更新正确的行,依此类推。

如果我选中图片#101 的另一张幻灯片,那么我需要为它创建一个新行。如果之后我想添加另一个language_id,那么我需要确保不添加新行,因为一个存在NULL值,并且只用新语言id替换NULL值。

它看起来真的很复杂,并且有很多因素,使用这种方法真的很难编程。

最好的方法是什么?任何建议都非常感谢。

谢谢!

3 个答案:

答案 0 :(得分:2)

您需要做的是在imagesslides / languages / types表之间实现N:M(多对多)关系,以便您的设计更加规范化(一个地方就是一个事实)。

以这种方式思考:一个image可以有多个slides,一个slide可以是多个images的选项。 - 这是N:M的关系。语言和类型也是如此。

您需要做的是摆脱包含 所有实体 之间选项的image_data表格,并改为使用三个单独的交叉引用表格。以下是您对其进行建模的方法:


基础表:

  

图片(image_id [PK],...)

     

幻灯片(slide_id [PK],slide_name,...)

     

语言(language_id [PK],language_name,...)

     

类型(type_name [PK],...)

交叉引用表:

  

images_has_slides (image_id [PK],slide_id [PK])

     

images_has_languages (image_id [PK],language_id [PK])

     

images_has_types (image_id [PK],type_name [PK])

它在ER中的表现如何:

Many-To-Many ER Diagram

使用这种类型的设计,您不必处理NULL值或计算要更新的行,因为您现在只在一个地方一个事实。要获得所有选项,您仍然必须这样做GROUP_CONCAT()

SELECT
    a.*,
    GROUP_CONCAT(c.slide_name) AS slides,
    GROUP_CONCAT(e.language_name) AS languages,
    GROUP_CONCAT(f.type_name) AS types
FROM
    images a
LEFT JOIN
    images_has_slides b ON a.image_id = b.image_id
LEFT JOIN
    slides c ON b.slide_id = c.slide_id
LEFT JOIN
    images_has_languages d ON a.image_id = d.image_id
LEFT JOIN
    languages e ON d.language_id = e.language_id
LEFT JOIN
    images_has_types f ON a.image_id = f.image_id
GROUP BY
    a.image_id

然后要更新图片选项,您可以在交叉引用表上使用INSERTDELETE

假设您想要为图像添加两种语言,您可以这样做

INSERT INTO images_has_languages (image_id, language_id) 
VALUES (101, 4), (101, 5);

上述查询会将ID为45的语言添加到ID为101的图片中。

删除选项(取消选中表单) - 假设您要从图片中删除2张幻灯片

DELETE FROM images_has_slides WHERE image_id = 101 AND slide_id IN (3,6)

这会从ID为3的图片中删除ID为6101的幻灯片。

因此,在您的应用程序中,您可以根据用户是否取消选中或检查图像表单中的值来确定是否需要插入/删除查询。

答案 1 :(得分:1)

您需要normalize您的架构。

  1. 你有images表:
  2.     CREATE TABLE images (
            image_id   integer,
            image_name varchar(100),
            PRIMARY KEY(image_id)
        );
    
    1. 每张图片可以包含多个slides
    2.     CREATE TABLE slides (
              slide_id   integer,
              image_id   integer,
              slide_name varchar(100),
              PRIMARY KEY(slide_id)
          );
      

      image_typesimage_languages也是如此。我希望你理解逻辑。并确保添加适当的FOREIGN KEY约束。此外,最好在下级表的CREATE INDEX列上image_id

      现在,相关表中的每个参数都有1行。管理内容应该很简单:INSERT选择某些功能时的新记录,取消选择这些功能时DELETE。查询(基于概述的2个表)应为:

      SELECT i.image_id, i.image_name,
             group_concat(s.slide_id) AS slides
        FROM images i
        LEFT JOIN slides s USING (image_id)
       GROUP BY i.image_id;
      

      一些注意事项:

      1. GROUP BY image_id PRIMARY KEY是安全的,因为它是iamges的{​​{1}},因此可以保证单行灌浆;
      2. 如果您希望从每个图片的1开始slide_id(也language_idtype_id和其他),您可能需要使用2字段主键在下属表格中,如PRIMARY KEY (image_id, slide_id)

      3. 修改

        关于many-to-many关系的说明。如果您碰巧拥有2组相关数据,例如images可以有多个slides而许多slide_id可以共享image_id,那么您需要一个额外的表:< / p>

        CREATE TABLE images (
            image_id   integer,
            image_name varchar(100),
            PRIMARY KEY(image_id)
        );
        
        CREATE TABLE slides (
            slide_id   integer,
            slide_name varchar(100),
            PRIMARY KEY(slide_id)
        );
        
        CREATE TABLE image_slides (
            image_id   integer,
            slide_id   integer,
            create_dt  timestamp,
            PRIMRY KEY (image_id, slide_id)
        );
        

答案 2 :(得分:1)

你试过拆分表吗?如果您为幻灯片和语言创建单独的表,并将类型保留在与图像ID相同的表中,则可以使用该表来创建列表。然后,您可以使用外键优化数据库,这样就不会对性能造成太大影响。

这就是我的意思:

图像数据表:两列,image_id和image_type(类型是保留字)。 Imageid是主键,因此没有重复项(假设您只想为每个图像使用一种类型)

图像语言表:两列,图像ID和image_language。两者都是主键,因此您不会在同一图像ID上复制语言,但图像ID可以包含多种语言。图像ID中的主键链接到图像数据表中的主键

图像幻灯片表:两列,图像ID和幻灯片编号。与上面相同(两个主键,关系等)

这样你就可以获得所有数据:

SELECT d.image_id, d.image_type, l.image_language, s.slide_number FROM image_data d LEFT JOIN image_language l ON d.image_id = l.image_id LEFT JOIN image_slide s ON s.image_id = s.image_id

左连接确保即使没有足够的语言或幻灯片,也无论如何都会显示所有项目ID。它将为您创建一个“矩阵”,每个图像和每种语言以及它适用的每个幻灯片都有一行。例如,如果您的图像具有西班牙语和英语作为其语言和4张幻灯片,您将获得8个条目:每种语言的每张幻灯片一个。

我不知道这是否一定能解决这个问题,但是如果让数据库为你做一些工作,它会更容易控制数据库中的确切内容。