1

我有两个表,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   |

所以基本上,每个图像都会有不同的选项,我想知道实现这一点的最佳方法..因为我觉得我做错了。

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

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

这很好,但我现在这样做的问题是……用我的后端系统更新行似乎真的很困难。

在此处输入图像描述

因此,通过我的查询,我可以根据数据库确定要检查哪些,因为自从我将它连接起来后,我将所有这些都放在一行中。但现在就像..当我点击“保存”并更新行时,我应该更新哪一个?可以有超过 1 行相同的图像 id,那么我将如何更新正确的,等等。

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

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

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

谢谢!

4

3 回答 3

2

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

可以这样想:一个image可以有多个slides,一个slide可能是多个的选项images。——这是一个 N:M 关系。语言和类型也是如此。

您需要做的是摆脱包含所有实体image_data之间选项的表,并改为使用三个单独的交叉引用表。以下是您将如何建模:


基表:

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

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

语言(language_id [PK], language_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 中的外观:

多对多 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 为 的语言添加到 id为45图像中101

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

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

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

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

于 2012-07-01T05:01:40.017 回答
1

您需要规范化您的架构。

  1. 你有images表:
    CREATE TABLE images (
        image_id   integer,
        image_name varchar(100),
        PRIMARY KEY(image_id)
    );
  1. 每个图像可以有几个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;

一些注意事项:

  1. GROUP BY只做是安全的image_id,因为它是 的PRIMARY KEYiamges因此它将保证单行分组;
  2. 如果您希望slide_id(alsolanguage_idtype_idothers) 从 1 开始为每个图像,您可能会在从属表中选择 2 字段主键,例如PRIMARY KEY (image_id, slide_id).

编辑:

关于多对多关系的注释。如果您碰巧有 2 组相关数据,例如imagescan have manyslides并且slide_id可以由 many 共享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)
);
于 2012-07-01T04:43:49.527 回答
1

您是否尝试过拆分表?如果您为幻灯片和语言制作一个单独的表格,并将类型与图像 ID 保存在同一个表格中,您就可以使用它来制作列表。然后,您可以使用外键优化您的数据库,这样您就不会受到太大的性能影响。

这就是我的意思:

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

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

Image-slide table:两列,image id和slide number。同上(两个主键、关系等)

通过这种方式,您可以获得所有数据,如下所示:

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 个条目:每种语言的每张幻灯片一个条目。

我不知道这是否一定会解决问题,但它会使准确控制数据库中的内容变得更容易一些,同时仍然让数据库为您做一些工作。

于 2012-07-01T04:52:53.307 回答