我有三张桌子
CREATE TABLE posts (
id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
slug VARCHAR(64) NOT NULL UNIQUE,
...
) ENGINE InnoDB ;
CREATE TABLE comments (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
post SMALLINT UNSIGNED REFERENCES posts(id) ON DELETE SET NULL,
...
) ENGINE InnoDB ;
CREATE TABLE visits (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
post SMALLINT UNSIGNED REFERENCES posts(id) ON DELETE SET NULL
...
) ENGINE InnoDB ;
这个查询
SELECT
posts.*,
DATE_FORMAT(posts.posted, '%W, %M %e, %Y') as d,
COUNT(visits.post) as views,
COUNT(comments.post) as comments
FROM posts
LEFT JOIN visits ON posts.id = visits.post
LEFT JOIN comments ON posts.id = comments.post
WHERE
posts.slug = '$slug'
AND posts.published = 1
AND posts.visible = 1 ;
不幸的是,views
和comments
最终都包含相同的值:评论数量乘以访问次数。任何一个计数/连接对都可以自己工作,但是一旦我将它们放在一起,我就会得到这个结果。那是为什么?
我最后尝试添加GROUP BY posts.id
,但没有区别。
由于slug
列包含唯一值,因此此查询应该只有一个结果。
答案 0 :(得分:0)
这不是“神秘的”。这是加入工作的方式。如果帖子有3次访问和4条评论,那么在聚合之前,您将从查询逻辑中获得12行。
在您的查询中,您可以使用count(distinct)
:
SELECT
posts.*,
DATE_FORMAT(posts.posted, '%W, %M %e, %Y') as d,
COUNT(distinct visits.id) as views,
COUNT(distinct comments.id) as comments
. . .
只要您没有针对特定帖子进行数百次访问和评论,这将有效。在这些情况下,您需要在进行连接之前预先聚合结果,或者在每个帖子的子查询中进行聚合。
答案 1 :(得分:0)
您想要在查询中添加group by post.id
子句。
当“on子句”匹配时,连接会导致“笛卡尔积”出现。 (左或右连接允许'缺失'ons返回空值而不是)。分组将告诉SQL采用该笛卡尔积,但将结果与匹配值组合在一起限制为单行。