如何查询多对多

Posted

技术标签:

【中文标题】如何查询多对多【英文标题】:How to query many to many 【发布时间】:2010-06-29 00:43:09 【问题描述】:

我正在尝试对这些字段进行多对多查询。我想得到:

1) 属于某个类别的所有帖子

2) 帖子中的所有类别

3) 属于某个类别且具有特定 ID 的所有帖子

    posts
+-------------+--------------+
| id          | int(11)      |
| title       | varchar(255) |
| body        | text         |
| parent_id   | int(11)      |
| category_id | int(11)      |
+-------------+--------------+
    post_categories 
+----------+--------------+
| id       | int(11)      |
| category | varchar(255) |
+----------+--------------+
    post_category_bridge
+-------------+-------------+
| id          | int(11)     |
| post_id     | int(11) |
| category_id | int(11) |
+-------------+-------------+

我担心的一件事是,我在 mysql DB 上使用 php 的 PDO 进行开发,但我将在发布当天将该站点转移到 SQL Server。我知道 MySQL 和 SQL Server 之间存在差异。 POD 会处理这些差异,还是我需要重新编写这些查询。

提前致谢。

【问题讨论】:

为什么post.idint(11)post_category_bridge.post_idtinyint(11)?这在创建外键时很常见吗? posts 表中不需要您的 category_id。这应该是您的“桥梁”或关系表的目的。 【参考方案1】:

我使用详细的连接语法来更清楚地了解表的相关性。

1) 属于某个类别的所有帖子

给定类别名称,您需要连接所有三个表。

select p.*
  from post_category c
    join post_category_bridge b on c.id = b.category_id
    join posts p                on p.id = b.post_id
  where c.category = ?

2) 帖子中的所有类别

给定post id,你只需要加入bridge和category表。

select c.*
  from post_category_bridge b
    join post_category c        on c.id = b.category_id
  where b.post_id = ?

3) 属于某个类别且具有特定 ID 的所有帖子

我认为您的意思是在这里查找category.id 的帖子(而不是category.name),这类似于(1)但不需要加入类别表,因为您已经知道 id;您只需要加入 bridge 和 post 表。

select p.*
  from post_category_bridge b
    join posts                  on p.id = b.post_id
  where b.category_id = ?

我将在发布当天将网站转移到 SQL Server...POD 会处理这些差异还是需要重新编写这些查询。

这取决于最终出现在您系统中的查询。如果您正在编写自己的 SQL,那么在开发过程中是否使用 MySQL 独有的功能或语法将很重要。我强烈建议在 SQL Server 很久之前 发布日进行测试,否则您可能会发现发布推迟了一段时间。您可以为此免费下载evaluation version。

cmets中提到的重复点:

正如@freddy 提到的,您不需要posts.category_id 字段。在多对多关系中,桥(又名“junction”、“join”、“map”、“link”等)表将帖子链接到多个类别 - posts 表上的单个字段将被使用,如果只允许一个类别。 正如@JamieWong 提到的,您应该保持表键和外键之间的类型一致,例如如果posts.idint(11),那么post_category_bridge.post_id 也应该是int(11)。大多数(全部?)强制外键约束的数据库都需要这个(包括 MySQL)。为什么?如果可以有 4294967295 个帖子(由 4 字节 int 支持),那么桥表中的意义不大,只支持链接到 255 个帖子(由 1 字节 tinyint 支持) 当你在做这件事时……不妨将 ID(以及这些 ID 的 FK)设为unsigned

【讨论】:

【参考方案2】:

这有帮助吗?

1:

select p.* from posts p, post_categories c
where p.category_id=c.id and category='something'

2:

select c.* from post_categories, posts p
where p.category_id=c.id and post_id=something

3:

select p.* from post_categories, posts p
where p.category_id=c.id and post_id=something and category='something'

【讨论】:

【参考方案3】:

select a.*  from posts a, post_categories b, post_category_bridge c 
WHERE 
     b.category="mycat" AND 
     b.id=c.category_id AND 
     a.id = c.post_id;

select b.category from posts a, post_categories b, post_category_bridge c,
WHERE
    c.post_id='PostID' AND
    b.id = c.category_id;


select a.*  from posts a, post_categories b, post_category_bridge c 
WHERE 
     b.category="mycat" AND 
     c.category_id = b.id AND 
     c.post_id = 'MyID' AND
     a.id = c.post_id;

【讨论】:

以上是关于如何查询多对多的主要内容,如果未能解决你的问题,请参考以下文章

Laravel:如何在多态中使用wherePivot多对多

Laravel:如何在多态多对多中使用 wherePivot

mybatis 一对一对多多对多对多

三大框架 之 Hibernate查询(一对多多对多查询关系)

Mybatis复杂映射开发:一对一一对多多对多查询

Mybatis注解开发:使用注解实现一对一一对多多对多查询