[英]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. 我有两个表, images和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 |
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). 您需要做的是在
images
和slides
/ 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:
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: 然后,要更新图像选项,您将在交叉引用表上使用
INSERT
和DELETE
:
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为
4
和5
语言添加到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为3
和6
幻灯片。
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. 您需要规范化架构。
images
table: images
表: CREATE TABLE images (
image_id integer,
image_name varchar(100),
PRIMARY KEY(image_id)
);
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_types
和image_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: 一些说明:
GROUP BY
only by image_id
, as it is a PRIMARY KEY
of the iamges
and thus it will guarantee single-row groupping; GROUP BY
仅image_id
,因为它是一个PRIMARY KEY
的的iamges
,因此它会保证单行groupping; 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)
. slide_id
(也是language_id
, type_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.