【问题标题】:PHP - MySQL queries over three tablesPHP - MySQL 查询三个表
【发布时间】:2012-07-08 17:46:25
【问题描述】:

基本上我拥有的是一个图片库。只是试图创建一个用于学习目的。我现在所拥有的是,当他/她单击类别时,会触发以下用于选择画廊的 mysql 查询:

从画廊 WHERE 中选择 ID、名称、gallery_thumb category1=$category_id 或 category2=$category_id 或 category3=$category_id ORDER BY ID DESC

这只是我拼凑起来的一个快速而糟糕的解决方案。基本上我希望一个画廊出现在许多类别中。在这里,我在创建画廊时这样做了,我可以将其添加到三个或更少的类别中,因此一个画廊可能会出现在不同的类别中。但这个灵魂不是我想要的。

画廊表:

创建表`画廊`(
`ID` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(1000) 字符集 utf8 整理 utf8_unicode_ci 非空, `description` varchar(1000) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `category1` varchar(500) 字符集 utf8 整理 utf8_unicode_ci 非空, `category2` varchar(500) 字符集 utf8 整理 utf8_unicode_ci 非空, `category3` varchar(500) 字符集 utf8 整理 utf8_unicode_ci 非空, `web_link` varchar(3000) 字符集 utf8 整理 utf8_unicode_ci 非空, `gallery_thumb` varchar(2000) 字符集 utf8 整理 utf8_unicode_ci 非空, `reg_time` 时间戳 NOT NULL DEFAULT CURRENT_TIMESTAMP, 主键(`ID`) )

category2 和 category3 将是不必要的,如果我得到我想要的功能,则将其删除。

标签表:

创建表`gallery_tags`( `ID` int(11) NOT NULL AUTO_INCREMENT, `tag_name` varchar(100) 字符集 utf8 整理 utf8_unicode_ci 非空, 主键(`ID`) )

标签和图库参考表:

创建表`gallery_tag_reference`( `ID` int(11) NOT NULL AUTO_INCREMENT, `gallery_id` int(11) NOT NULL, `tags_id` int(100) NOT NULL, 主键(`ID`) )

我添加了标签功能。当我现在创建一个画廊时,我可以向画廊添加任意数量的标签。现在画廊将只有一个主要类别和许多与之相关的标签。但我希望画廊也能根据我在创建画廊时添加的标签出现在其他类别中。这些类别将有一个或多个预定义的标签。我现在想要做的是,当访问者点击类别时,将选择相同的数据,而之前只有查询过滤部分会有所不同。

示例:

类别 1 将有标签:汽车、蓝色、闪亮
画廊 1 将有标签:蓝色、红色、快速。
Gallery1 不属于 category1,但因为它在表“gallery_tags”中添加了一个标签“blue”,所以它出现在访问者单击 category1 按钮时执行的查询结果中。

示例 2:

Category1 将没有标签。
Category2 将没有标签。
Category3 将没有标签。
Category4 将具有预定义的标签:黄色、红色。
Category5 将具有预定义的标签:高、高。

Gallery1 将没有标签,但它属于 Category1。
Gallery2 将没有标签,但它属于 Category2。
Gallery3 将有标签:黄色、高大、田野
Gallery3 属于 Category3。

当访问者点击 Category4 按钮时,选择的是属于 Category4 的画廊和带有“黄色”或“红色”标签的画廊。因为这里我们没有属于 Category4 的画廊,但是我们有 gallery3,它有标签黄色,并且 Category4 也有预定义的标签“黄色”,当点击时,画廊 3 会显示在 Category4 中。

Category5 也是如此。它没有直接属于它的任何画廊,但是因为画廊 3 有一个与之相关的标签“高”,并且类别 5 也有预定义的标签“高”,所以画廊 3 也显示在类别 5 中。

我希望我清楚地描述了我想要实现的目标。由于我在 MySQL 方面不是很有经验,所以我很难将必要的查询放在一起。希望有人能帮忙!

【问题讨论】:

    标签: mysql sql create-table


    【解决方案1】:

    好的,所以您的基本选择单位是 tagcategrory - 让我们从为它们创建表格开始

    CREATE TABLE tags (
      id INT PRIMARY KEY AUTO_INCREMENT,
      name VARCHAR(100) NOT NULL,
      -- Maybe some other things you want? Tag description?
      UNIQUE INDEX name
    );
    

    这给了我们一个tags 表,我们可以用

    INSERT INTO tags(name) VALUES
      ('car'),('blue'),('shiny'),('red'),('fast'),('yellow'),('tall'),('high'),('field')
    ;
    

    基本上同样的事情发生在类别上:

    CREATE TABLE categories (
      id INT PRIMARY KEY AUTO_INCREMENT,
      name VARCHAR(100) NOT NULL,
      -- Maybe some other things you want? Description?
      UNIQUE INDEX name
    );
    
    INSERT INTO categories(name) VALUES
      ('cars'),('people'),('colors'),('landscapes'),('misc')
    ;
    

    现在我们可以看看画廊了:

    • 每个画廊都应该恰好属于 1 个类别(现在),每个 类别可以有很多画廊。所以这是一个1:n 关系 类别的 POV,所以我们需要在n-side 中的指针字段 的关系,画廊。我这里不使用外键 只是为了简洁,强烈建议您考虑使用它们。
    • 每个画廊可以有很多标签,每个标签可以属于很多画廊 - 所以这是一个 n:m 关系,我们不需要直接在表中的字段,但我们需要一个连接表。
    • 每个类别可以有很多标签,每个标签可以属于很多类别 - 所以是一样的

    所以我们这样做:

    CREATE TABLE galleries (
      id int(11) PRIMARY KEY AUTO_INCREMENT,
      name varchar(100)  NOT NULL,
      category` INT NOT NULL,
      -- the other fields you want: description, web_link, gallery_thumb,reg_time
      UNIQUE INDEX(name)
    )
    

    注意类别的数据类型INT:它将链接到类别表的主键,也就是INT

    我们可能不会忘记连接表:

    CREATE TABLE galleries_tags (
      gallery INT,
      tag INT,
      PRIMARY KEY(tag, gallery),
      KEY(gallery)
    );
    
    CREATE TABLE categories_tags (
      category INT,
      tag INT,
      PRIMARY KEY(tag, category),
      KEY(category)
    );
    

    INT 类型的 tag 字段将这些连接表链接到 tags 表的 id 字段,而 gallery 分别链接到表。 category 字段将链接到各个表的 id 字段。

    我们再次用INSERT 查询填充表。 (懒得写出来)

    现在您的数据已在数据库中,是时候再次将其取出:

    你的用例:用户点击一个类别,你想选择画廊,有

    • 在此类别下提交
    • 或与此类别共享标签

    这很容易,但需要一点思考:

    • 您的目标表是categories
    • 对于按类别进行选择,您有一个直接选择器:category 字段
    • 对于标签选择,您必须通过上述连接表进行连接
    • 对于组合选择,如果您不想错过仅限类别的选择,则需要LEFT JOIN,但这会影响您的表现。所以你选择单独和UNION结果

    假设您的用户选择了类别 4:

    SELECT * FROM galleries WHERE category=4
    UNION
    SELECT categories.* 
    FROM galleries
    INNER JOIN galleries_tags ON galleries.id=galleries_tags.gallery
    INNER JOIN categories_tags ON categories_tags.tag=galleries_tags.tag
    WHERE categories_tags.category=4
    

    鲍勃是你的叔叔。

    这个查询有什么作用?第一部分很简单,第二部分选择那些画廊,那

    • 已附加标签 (INNER JOIN galleries_tags ON ...)
    • 哪些标签附加了类别 (INNER JOIN categories_tags ON ...)
    • 哪些类别有id 4

    【讨论】:

      猜你喜欢
      • 2010-12-15
      • 1970-01-01
      • 1970-01-01
      • 2015-05-22
      • 2012-05-02
      • 2013-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多