繁体   English   中英

当三个表连接时,MySQL不返回任何内容。 两个表在第三个表中有外键。 怎么了?

[英]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小提琴: http ://sqlfiddle.com/#!9 / a9143 / 2

我有表“ 文章 ”,“ 发布 ”和评论 (在我的真实数据库中,这是另一回事,我只是在这里做一个例子)。 在“ 注释 ”表中,我有外键“ source_id ”,将此注释表与“ article ”和“ post ”表连接起来。 这是因为文章和帖子的id将是唯一的,永远不会发生冲突。

我的意思是,如果你看一下我的小提琴例子,你会看到帖子的ID是2001和2002,而文章的ID是3001和3002.而且永远不会发布id为3001或id为2001的文章(我知道你可能会认为这会发生,但事实并非如此,因为在实际系统中,这些ID不会自动递增)。

如您所见,我想从所有3个表中选择数据,但我什么都没得到。 输出应该是这样的:

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

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

您的数据库结构意味着从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表(或任何您想要调用它)上有一个type列,以确定它是一个帖子还是一篇文章。 这仅适用于所有(或至少大多数)列可用于所有类型的情况。
  • 或者,如果各种类型的格式不同,可能值得将您的公共字段放在written_work (我称之为公共表或集合表),然后在必要时添加“specializing”表。 这些字段包含仅在文章或帖子中使用的字段,并且每个书面工作类型都有一个字段。 written_work与指定类型的专家表之间的关系是1:1。

如果您可以避免“重复使用”外键,您将能够使用外键约束,这将使您对数据的完整性更有信心。 您目前的设计无法实现。

问题是每个评论都属于文章或帖子,但不属于两者。 通过在页面和文章表上执行内部联接,您可以查找附加到两者的注释,以及那些不存在的注释。

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

当您连接到“post”或“article”表时,这些应该是LEFT OUTER JOIN而不是INNER JOIN。 INNER JOIN在有帖子和文章同时连接到评论时起作用。

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

编辑。 它可以在我的本地副本中工作,但由于SQL小提琴是错误的,不能只显示带有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小提琴中不起作用):

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
;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM