4
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_submissionsandnum_comments变量显示正确的结果,而total_pointsand显示,和month_points的乘积。知道为什么会这样吗?month_points/total_pointslive_submissionsnum_comments

4

3 回答 3

11

这称为笛卡尔积。将表连接在一起时,默认结果是连接条件为真的行的每个排列。您使用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;

您不应该尝试在一个查询中完成所有这三个操作。

于 2009-04-02T01:24:12.057 回答
0

你能提供一些示例输出吗?

我认为这与在要点中添加咆哮和评论有关。您可以尝试删除咆哮和评论表吗?

于 2009-04-02T00:13:10.950 回答
-1

如果您在分组之前查看查询输出,那么您会发现问题。如果用户在任何连接表中有超过 1 条记录,则将为用户返回多行。因此,如果用户有 2 条评论记录,那么也会返回 2 条点记录。

作为一个简化的例子......

用户表

用户名

1 弗雷德

点表

userId 积分

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
于 2009-04-02T00:23:54.543 回答