MySQL return 连接三个表时没有任何内容。两个表在第三个表中有外键。怎么了?

MySQL return nothing when three tables are joined. Two tables have foreign keys in third one. What is wrong?

下面的结构和查询非常简单,但我不明白为什么我没有得到任何结果:

SELECT * FROM `comment` 
JOIN post    ON comment.source_id = post.id 
JOIN article ON comment.source_id = article.id

这里是 SQL Fiddle: http://sqlfiddle.com/#!9/a9143/2

我有tables“文章”、“post”和 comment(在我的真实数据库中这是另外一回事,我只是在这里举个例子)。在“评论”table中,我有外键“source_id”,将此评论table与“文章”和“post”table。这是因为文章的 id 和 post 是唯一的,永远不会冲突。

我的意思是,如果你看我的 fiddle 示例,你会看到 post id 是 2001 和 2002,而文章 id 是 3001 和 3002。而且永远不会 post with id of 3001 or article with id of 2001 (我知道你可能认为这会发生,但它不会,因为在真实系统中,这些ids不会自动递增)。

如您所见,我想要 select 来自所有 3 table 的数据,但我什么也没得到。输出应该是这样的:

id      source_id   text                id      title
 1      2001        First comment       2001    First post
 2      2002        Second comment      2002    Second Post
 3      3001        Third comment       3001    First article
 4      3002        Comment on article  3002    Second article

我做错了什么吗?或者这是不可能的?

当您连接到 "post" 或 "article" table 时,这些应该是 LEFT OUTER JOIN 而不是 INNER JOIN。当 post 和一篇文章都连接到评论时,INNER JOIN 起作用。

SELECT * FROM `comment` 
LEFT JOIN post    ON comment.source_id = post.id 
LEFT JOIN article ON comment.source_id = article.id
;

编辑。它在我的本地副本中有效,但由于 SQL fiddle 有很多问题,不能只显示 NULL 行的结果,我可以给你一个例子,在那里显示这种思维方式实际上是正确

SELECT 
comment.id as comment_id,  
source_id,
text,
IF(post.id IS NOT NULL, post.id, 0) as post_id,  
IF(post.title IS NOT NULL, post.title, 0) as post_title,
IF(article.id IS NOT NULL, article.id, 0) as article_id,  
IF(article.title IS NOT NULL, article.title, 0) as article_title
FROM `comment` 
LEFT JOIN post    ON comment.source_id = post.id 
LEFT JOIN article ON comment.source_id = article.id
;

我还建议在此处为选择设置别名以供以后处理。因此,您副本中的最终查询应该是(由于 NULL,此查询在 SQL fiddle 中不起作用):

SELECT 
comment.id as comment_id,  
source_id,
text,
post.id as post_id,  
post.title as post_title,
article.id as article_id,  
article.title as article_title
FROM `comment` 
LEFT JOIN post    ON comment.source_id = post.id 
LEFT JOIN article ON comment.source_id = article.id
;

您的数据库结构暗示了从 commentpost 以及从 commentarticle 的关系。您需要分别对待这些,然后将两者合并:

SELECT * FROM `comment` 
JOIN post    ON comment.source_id = post.id 
UNION
SELECT * FROM `comment` 
JOIN article ON comment.source_id = article.id

这将适用于您的示例,因为并集的每一半的列格式都是兼容的。但是,如果您的实际用例有不同的列,您最好重新设计您的数据库。您可以采用两种方法:

  • written_work table 上有一个 type 列(或者你想怎么称呼它)以确定它是 post 还是一篇文章。这仅在所有(或至少大部分)列可用于所有类型时才有效。
  • 或者,如果各种类型的格式不同,可能值得将您的公共字段放在 written_work 中(我称之为公共或集体 table),然后添加 "specialising" tables 如有必要。这些包含仅在文章或 post 中使用的字段,并且每种书面作业类型都有一个。 written_work 和指定类型的专家 table 之间的关系是 1:1。

如果可以避免 "re-using" 外键,您将能够使用外键约束,这将使您对数据的完整性更有信心。你目前的设计是不可能的。

问题是每条评论要么属于一篇文章,要么属于 post,但不属于两者。通过在页面和文章 table 上执行内部联接,您正在寻找附加到两者的评论,而这些评论不存在。

这些是典型的一对多关系,您可以通过多种方式重新设计架构以更好地处理它们。例如,对于每个不同的内容类型,您可以添加 [content_type]_comment table 以将内容映射到评论。