SELECT user_id,
SUM(COALESCE(point_points, 0)) AS total_points,
SUM(
CASE
WHEN point_date > '$this_month'
THEN point_points
ELSE 0
END) AS month_points,
COUNT(DISTINCT c_id) AS num_comments,
COUNT(DISTINCT rant_id) AS live_submissions
FROM users
LEFT JOIN points
ON users.user_id = points.point_userid
LEFT JOIN comments
ON
(
c_userid = user_id
)
LEFT JOIN rants
ON
(
rant_poster = user_id
AND rant_status = 1
)
WHERE user_id = $id
GROUP BY user_id
基本上live_submissions
和num_comments
变量会显示正确的结果,而total_points
和month_points
会显示month_points/total_points
,live_submissions
和{num_comments
的产品{1}}。知道为什么会这样吗?
答案 0 :(得分:9)
这称为Cartesian Product。将表连接在一起时,默认结果为行的每个排列,其中连接条件为true。您使用JOIN
条件来限制这些排列。
但是,由于您要将多个表连接到users
,因此结果包括每个匹配表的每个排列。例如,points
中每个匹配行重复comments
中的每个匹配行,并且每个匹配行再次相乘,重复rants
中每个匹配的行。
您可以使用COUNT(DISTINCT c_id)
进行部分补偿,但DISTINCT
只是因为每个c_id
有多行才有必要。除非将其应用于唯一值,否则它不起作用。此补救措施不适用于SUM()
表达式。
基本上,您尝试在一个查询中进行太多计算。您需要将其拆分为单独的查询,以使其可靠。然后你也可以摆脱DISTINCT
修饰符。
SELECT u.user_id, SUM(COALESCE(p.point_points, 0)) AS total_points,
SUM( CASE WHEN p.point_date > '$this_month' THEN p.point_points ELSE 0 END ) AS month_points
FROM users u LEFT JOIN points p
ON u.user_id = p.point_userid
WHERE u.user_id = $id
GROUP BY u.user_id;
SELECT user_id, COUNT(c.c_id) as num_comments,
FROM users u LEFT JOIN comments c
ON (c.c_userid = u.user_id)
WHERE u.user_id = $id
GROUP BY u.user_id;
SELECT u.user_id, COUNT(r.rant_id) as live_submissions
FROM users u LEFT JOIN rants r
ON (r.rant_poster = u.user_id AND r.rant_status = 1)
WHERE u.user_id = $id
GROUP BY u.user_id;
您不应该尝试在单个查询中执行所有这三个操作。
答案 1 :(得分:0)
你能提供一些样本输出吗?
我认为这与点数中添加咆哮和评论有关。你能尝试删除rants和comments表吗?
答案 2 :(得分:-1)
如果在分组之前查看查询输出,那么您将看到问题。如果用户在任何已连接的表中具有多个记录,则将为该用户返回多行。因此,如果用户有2条评论记录,那么也会返回2点记录。
作为一个简化的例子......
用户表
userId名称
1弗雷德
点位表
userId Points
1 10
评论表
userId评论
1这里
1那里
从这些表中选择*将导致
userId点评论
1 10这里
1 10那里
我不完全确定MYSQL语法,但你会想要像
这样的东西SELECT UserId, C.num_comments, P.total_points
FROM users
LEFT JOIN
(SELECT c_userId, COUNT(DISTINCT c_id) as num_comments
FROM Comments
GROUP BY c_userId)
AS C
ON UserId = c_userid
LEFT JOIN
(SELECT point_userId, sum(COALESCE(point_points, 0)) as total_points
FROM Points
GROUP BY point_userId)
AS P
ON UserId = point_userid