我有两张表,图片和 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 |
哪个好,但我现在这样做的问题是......看起来用我的后端系统更新行真的很难。
因此,根据我的查询,我可以根据数据库确定要检查哪些数据库,因为我将它连接在一起,因为我将它连接起来。但是现在它就像..当我点击“保存”并更新行时,我会更新哪一行?相同的图像ID可以有多于一行,所以如何更新正确的行,依此类推。
如果我选中图片#101 的另一张幻灯片,那么我需要为它创建一个新行。如果之后我想添加另一个language_id,那么我需要确保不添加新行,因为一个存在NULL值,并且只用新语言id替换NULL值。
它看起来真的很复杂,并且有很多因素,使用这种方法真的很难编程。
最好的方法是什么?任何建议都非常感谢。
谢谢!
答案 0 :(得分:2)
您需要做的是在images
和slides
/ 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中的表现如何:
使用这种类型的设计,您不必处理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
然后要更新图片选项,您可以在交叉引用表上使用INSERT
和DELETE
:
假设您想要为图像添加两种语言,您可以这样做
INSERT INTO images_has_languages (image_id, language_id)
VALUES (101, 4), (101, 5);
上述查询会将ID为4
和5
的语言添加到ID为101
的图片中。
删除选项(取消选中表单) - 假设您要从图片中删除2张幻灯片
DELETE FROM images_has_slides WHERE image_id = 101 AND slide_id IN (3,6)
这会从ID为3
的图片中删除ID为6
和101
的幻灯片。
因此,在您的应用程序中,您可以根据用户是否取消选中或检查图像表单中的值来确定是否需要插入/删除查询。
答案 1 :(得分:1)
您需要normalize您的架构。
images
表: CREATE TABLE images (
image_id integer,
image_name varchar(100),
PRIMARY KEY(image_id)
);
slides
: CREATE TABLE slides (
slide_id integer,
image_id integer,
slide_name varchar(100),
PRIMARY KEY(slide_id)
);
image_types
和image_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;
一些注意事项:
GROUP BY
image_id
PRIMARY KEY
是安全的,因为它是iamges
的{{1}},因此可以保证单行灌浆; slide_id
(也language_id
,type_id
和其他),您可能需要使用2字段主键在下属表格中,如PRIMARY KEY (image_id, slide_id)
。修改强>
关于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个条目:每种语言的每张幻灯片一个。
我不知道这是否一定能解决这个问题,但是如果让数据库为你做一些工作,它会更容易控制数据库中的确切内容。