简体   繁体   English

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

[英]MySQL database design for image options relationships

I have two tables, images and image_data and here is an example of my image_data table. 我有两个表, imagesimage_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   |

So basically, each image will have different options and I am wondering the best way to implement this.. because I have a feeling I am doing this the wrong way. 所以基本上,每个图像都有不同的选项,我想知道实现这个的最好方法..因为我有一种感觉,我这样做是错误的。

With this, I can run a query to use GROUP_CONCAT() to turn values in multiple rows into a single concatenated string. 有了这个,我可以运行一个查询来使用GROUP_CONCAT()将多行中的值转换为单个连接字符串。

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

Which is fine, but the problem with the way I am doing it right now is..it seems like it will be really difficult to update the rows with my backend system. 这很好,但我现在正在做的方式的问题是..看起来用我的后端系统更新行真的很难。

在此输入图像描述

So with my query, I can determine which ones to check based on the database since I have it all in one row since I concatenated it. 因此,根据我的查询,我可以根据数据库确定要检查哪些数据库,因为自从我连接它以来我将它全部放在一行中。 But now it's like.. when I go to click "Save" and update the rows, which one do I update? 但是现在它就像..当我点击“保存”并更新行时,我会更新哪一行? there can be more than 1 row of the same image id, so how would I update the right one, and so on. 相同的图像ID可以有多于一行,所以如何更新正确的行,依此类推。

If I checked off another slide for image #101 then I would need to create a new row for it. 如果我检查了图像#101的另一张幻灯片,那么我需要为它创建一个新行。 If after that I wanted to add another language_id to it, then I would need to make sure to not add a new row since one exists with a NULL value, and to just replace the NULL value with the new language id. 如果之后我想添加另一个language_id,那么我需要确保不添加新行,因为一个存在NULL值,并且只用新语言id替换NULL值。

It just seems really complicated and there's so many factors, that using this method is really hard to program. 它看起来真的很复杂,并且有很多因素,使用这种方法真的很难编程。

What would be the best way to do this? 最好的方法是什么? Any suggestions are really appreciated. 任何建议都非常感谢。

Thanks! 谢谢!

What you need to do is implement N:M (many-to-many) relationships between your images and slides / languages / types tables so that your design is more normalized (one fact in one place). 您需要做的是在imagesslides / languages / types表之间实现N:M(多对多)关系,以便您的设计更加规范化(一个地方就是一个事实)。

Think of it this way: one image can have multiple slides , and one slide may be an option of multiple images . 可以这样想:一个image可以有多个slides ,一个slide可以是多个images的选项。 -- this is a N:M relationship. - 这是N:M的关系。 Same goes for languages and types. 语言和类型也是如此。

What you need to do is get rid of your image_data table which houses the options between ALL entities and have three separate cross-reference tables instead. 你需要做的是摆脱你的image_data表,它包含所有实体之间的选项,而是有三个独立的交叉引用表。 Here's how you would model it: 以下是您对其进行建模的方法:


Base tables: 基表:

images (image_id [PK], ...) 图像 (image_id [PK],...)

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

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

types (type_name [PK], ...) types (type_name [PK],...)

Cross-Reference tables: 交叉参考表:

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

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

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

How it would look in ER: 如何看待ER:

多对多ER图

With this type of design, you wouldn't have to deal with NULL values or figuring out which row to update because you now have just one fact in one place . 使用这种类型的设计,您不必处理NULL值或找出要更新的行,因为您现在只在一个地方一个事实 To get all options, you would still have to do GROUP_CONCAT() like so: 要获得所有选项,您仍然需要像这样执行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

Then to update image options, you would use INSERT and DELETE on the cross-reference tables: 然后,要更新图像选项,您将在交叉引用表上使用INSERTDELETE

Let's say you wanted to add two languages to an image, you would do 假设您想要为图像添加两种语言,您可以这样做

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

The above query adds languages with id's of 4 and 5 to the image that has an id of 101 . 上面的查询将id为45语言添加到id为101的图像中。

To remove options (unchecking on the form) - let's say you wanted to remove 2 slides from an image 要删除选项(取消选中表单) - 假设您要从图像中删除2张幻灯片

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

This removes slides with id's of 3 and 6 from the image that has an id of 101 . 这将从ID为101的图像中删除ID为36幻灯片。

So in your application, you could figure out if you need to do insert/delete queries based on if the user unchecked or checked values in the form for the image. 因此,在您的应用程序中,您可以根据用户是否取消选中或检查图像表单中的值来确定是否需要插入/删除查询。

You need to normalize your schema. 您需要规范化架构。

  1. You have images table: 你有images表:
    CREATE TABLE images (
        image_id   integer,
        image_name varchar(100),
        PRIMARY KEY(image_id)
    );
  1. Each image can have several slides : 每张图片都有几张slides
    CREATE TABLE slides (
        slide_id   integer,
        image_id   integer,
        slide_name varchar(100),
        PRIMARY KEY(slide_id)
    );

The same goes for the image_types and image_languages . image_typesimage_languages I hope you understand the logic. 我希望你理解逻辑。 And make sure to add proper FOREIGN KEY constraints. 并确保添加适当的FOREIGN KEY约束。 Also, it is a good idea to CREATE INDEX on the image_id columns of the subordinate tables. 此外,在下级表的image_id列上CREATE INDEX是个好主意。

Now, you have 1 row per each parameter in the related tables. 现在,相关表中每个参数有1行。 Managing the contents should be easy: INSERT new records when some features are selected and DELETE them when those are deselected. 管理内容应该很简单:在选择某些功能时INSERT新记录,并在取消选择这些功能时DELETE它们。 The query (based on the outlined 2 tables) should be: 查询(基于概述的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;

Some notes: 一些说明:

  1. It is safe to do GROUP BY only by image_id , as it is a PRIMARY KEY of the iamges and thus it will guarantee single-row groupping; 它是安全的GROUP BYimage_id ,因为它是一个PRIMARY KEY的的iamges ,因此它会保证单行groupping;
  2. If you'd like to have slide_id (also language_id , type_id and others) starting from 1 for each of the images, you might go for a 2-field primary keys in the subordinate table, like PRIMARY KEY (image_id, slide_id) . 如果您希望从每个图像的1开始使用slide_id (也是language_idtype_id和其他),您可以在下级表中使用2字段主键,如PRIMARY KEY (image_id, slide_id)

EDIT: 编辑:

A note on the many-to-many relations. 关于多对多关系的说明。 If you happen to have 2 sets of related data, like images can have many slides and slide_id can be shared by many image_id , then you need an extra table: 如果你碰巧有2组相关数据,比如images可以有很多slides而且slide_id可以被很多image_id共享,那么你需要一个额外的表:

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)
);

Have you tried splitting the tables? 你试过拆分表吗? If you make a separate table for the slide and language and kept the type in the same table as the image ID you could then use that to make your lists. 如果您为幻灯片和语言创建单独的表,并将类型保留在与图像ID相同的表中,则可以使用该表来创建列表。 You could then optimize your database with foreign keys so you don't take as big a performance hit. 然后,您可以使用外键优化数据库,这样您就不会受到太大的性能影响。

Here what I mean: 这就是我的意思:

Image data table: two columns, image_id and image_type (type is a reserved word). 图像数据表:两列,image_id和image_type(类型是保留字)。 Imageid is the primary key so there are no duplicates (assuming you only want one type for each image) Imageid是主键,因此没有重复项(假设您只想为每个图像使用一种类型)

Image-language table: two columns, image id and image_language. 图像语言表:两列,图像ID和image_language。 Both are primary keys so you don't duplicate languages on the same image id, but an image id can have multiple languages. 两者都是主键,因此您不会在同一图像ID上复制语言,但图像ID可以包含多种语言。 Primary key from image id links to the primary key in the image data table 图像ID中的主键链接到图像数据表中的主键

Image-slide table: two columns, image id and slide number. 图像幻灯片表:两列,图像ID和幻灯片编号。 Same as above (two primary keys, relationship, etc) 与上面相同(两个主键,关系等)

This way you could get get all the data like so: 这样你就可以获得所有数据:

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

The left joins make sure all the item id always shows up no matter what even if there isn't enough languages or slides to go around. 左连接确保即使没有足够的语言或幻灯片,也无论如何都会显示所有项目ID。 It will create a "matrix" of sorts for you with a row for each image and each language and each slide it applies to. 它将为您创建一个“矩阵”,每个图像和每种语言以及它适用的每个幻灯片都有一行。 For example, if you had an image that had spanish and english as its language and 4 slides, you would get 8 entries: one for each slide in each language. 例如,如果您的图像具有西班牙语和英语作为其语言和4个幻灯片,您将获得8个条目:每种语言的每张幻灯片一个。

I don't know if that will necessarily solve the problem, but it would make it a little easier to control exactly what is in the database while still having the database do a bit of the work for you. 我不知道这是否一定能解决这个问题,但是如果仍然让数据库为你做一些工作,它会更容易控制数据库中的确切内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM