通过链接表进行多条件连接

时间:2013-06-03 21:55:03

标签: mysql

请耐心等待,这需要很多前期信息来解释我想要做的事情。我试图尽可能地将其泛化以使事情更清楚。在一个查询中,我希望提取一个与另一个表中链接的标签匹配的页面列表,这些标签是分组的。我希望使用项目的文本表示而不是它的id,但如果没有别的我可以做2个前面的查询来获取tag_id和taggroup_id - 只是希望不必这样做。

DB Schema:

+-----------------------------------+
| taggroups                         |
+------------------+----------------+
| taggroup_id      | group_name     |
+------------------+----------------+
| 1                | fruits         |
+------------------+----------------+

+-----------------------------------------------+
| tags                                          |
+-------------+-----------------+---------------+
| tag_id      | taggroup_id     | tag_name      |
+-------------+-----------------+---------------+
| 1           | 1               | apple         |
| 2           | 1               | orange        |
| 3           | 1               | grape         |
+-------------+-----------------+---------------+

+--------------------------------------+
| pages                                |
+------------------+-------------------+
| page_id          | title             |
+------------------+-------------------+
| 99               | Doctor a day      |
+------------------+-------------------+

+--------------------------------------------------+
| tags_to_pages                                    |
+------------+----------+---------------+----------+
| join_id    | tag_id   | taggroup_id   | page_id  |
+------------+----------+---------------+----------+
| 1          | 1        | 1             | 99       |
| 2          | 2        | 1             | 99       |
+------------+----------+---------------+----------+

测试查询: 到目前为止,似乎无法让它发挥作用。

SELECT
    pages.*, tags.tag_name, taggroups.group_name
FROM
    tags_to_pages
    INNER JOIN taggroups as grp ON (
            grp.group_name = 'fruits'
        AND
            tags_to_pages.taggroup_id = grp.taggroup_id
    )
    INNER JOIN tags as val ON (val.tag_name = 'apple' AND tags_to_pages.tag_id = val.tag_id)
    LEFT JOIN pages ON (tags_to_pages.page_id = pages.page_id)

此外,哪些表应该有索引以及索引应该用于优化?

1 个答案:

答案 0 :(得分:0)

我这样做:

SELECT
    pages.*, tags.tag_name, taggroups.group_name
FROM
    tags_to_pages
    JOIN taggroups AS grp ON grp.taggroup_id = tags_to_pages.taggroup_id
    JOIN tags AS val ON val.taggroup_id = grp.taggroup_id
    JOIN pages ON tags_to_pages.page_id = pages.page_id
WHERE
    grp.group_name='fruits'
    AND val.tag_name = 'apple'

这不是 与您所拥有的不同,但我将加入条件放在JOIN子句和WHERE子句中的选择条件中,这对我来说似乎更整洁。

在重新输入此查询时,我发现您在某个地方使用了tag_id,我认为应该是taggroup_id,所以我更改了它,但我很遗憾现在无法再看到它。

我也担心选择标准 - 如果苹果没有成为水果怎么办?显然它是在这种情况下,实际上是在实际上:-),但我认为你应该只在查询中指定水果名称,而不是水果和组名,并让数据库为自己排序。

另外,为什么对标签,tags_to_pages和taggroups以及页面的OUTER JOIN使用INNER JOIN?当然,如果没有页面,你最好不要返回任何行而不是一行,在NULLS上半满?

我只会为id列编制索引。

真的是我的2p值。

修改

我已在www.sqlfiddle.com上设置了此演示。我更改SELECT列表中的别名后,original query工作正常。我的attempt above效果不是很好:-(。我对别名有同样的问题,一旦我修复它们,查询就会返回同一行两次。

我再次从头开始重写它

SELECT pages.*, tags.tag_name, taggroups.group_name
FROM pages
JOIN tags_to_pages AS ttp ON ttp.page_id = pages.page_id
JOIN tags ON tags.tag_id = ttp.tag_id
JOIN taggroups ON taggroups.taggroup_id = ttp.taggroup_id
WHERE taggroups.group_name = 'fruits' AND tags.tag_name='apple';

它工作正常link

设置此演示,让我想知道为什么要在taggroup_id表中保存tags_to_pages。我在SQL和数据库中“自学成才”(将其翻译为:“我随身携带,依靠做”工作“并相信直觉来找出'正确'的东西”)但不是这打破了正常化的想法吗? tagstaggroups之间的关联不应仅通过taggroup_id表中的tags列进行定义吗?也许真正了解数据库的人会出现并让我正确。

最后,我不知道为什么PHPMyAdmin在您尝试查询时会挂起。祝你好运!