[英]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
难道我做错了什么 ? 或者这是不可能的?
您的数据库结构意味着从comment
到post
,从comment
到article
。 您需要单独处理这些,然后将两者合并:
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.