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
;
您的数据库结构暗示了从 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
table 上有一个 type
列(或者你想怎么称呼它)以确定它是 post 还是一篇文章。这仅在所有(或至少大部分)列可用于所有类型时才有效。
- 或者,如果各种类型的格式不同,可能值得将您的公共字段放在
written_work
中(我称之为公共或集体 table),然后添加 "specialising" tables 如有必要。这些包含仅在文章或 post 中使用的字段,并且每种书面作业类型都有一个。 written_work
和指定类型的专家 table 之间的关系是 1:1。
如果可以避免 "re-using" 外键,您将能够使用外键约束,这将使您对数据的完整性更有信心。你目前的设计是不可能的。
问题是每条评论要么属于一篇文章,要么属于 post,但不属于两者。通过在页面和文章 table 上执行内部联接,您正在寻找附加到两者的评论,而这些评论不存在。
这些是典型的一对多关系,您可以通过多种方式重新设计架构以更好地处理它们。例如,对于每个不同的内容类型,您可以添加 [content_type]_comment
table 以将内容映射到评论。
下面的结构和查询非常简单,但我不明白为什么我没有得到任何结果:
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
;
您的数据库结构暗示了从 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
table 上有一个type
列(或者你想怎么称呼它)以确定它是 post 还是一篇文章。这仅在所有(或至少大部分)列可用于所有类型时才有效。 - 或者,如果各种类型的格式不同,可能值得将您的公共字段放在
written_work
中(我称之为公共或集体 table),然后添加 "specialising" tables 如有必要。这些包含仅在文章或 post 中使用的字段,并且每种书面作业类型都有一个。written_work
和指定类型的专家 table 之间的关系是 1:1。
如果可以避免 "re-using" 外键,您将能够使用外键约束,这将使您对数据的完整性更有信心。你目前的设计是不可能的。
问题是每条评论要么属于一篇文章,要么属于 post,但不属于两者。通过在页面和文章 table 上执行内部联接,您正在寻找附加到两者的评论,而这些评论不存在。
这些是典型的一对多关系,您可以通过多种方式重新设计架构以更好地处理它们。例如,对于每个不同的内容类型,您可以添加 [content_type]_comment
table 以将内容映射到评论。