MySQL查询涉及SUM,JOIN和SUM之间的区别

时间:2016-01-12 03:57:28

标签: mysql join

我希望得到用户(alpha)和他所有朋友之间的头部结果。

users
+--------+-------+
| userID | name  |
+--------+-------+
|      1 | alpha |
|      2 | beta  |
|      3 | gamma |
|      4 | delta |
+--------+-------+

relationships
+--------------+--------------+------------+
| user1_userID | user2_userID | friendship |
+--------------+--------------+------------+
|            1 |            2 |          1 |
|            1 |            3 |          1 |
|            1 |            4 |          0 |
+--------------+--------------+------------+

games
+-------+-------+--------------------+--------------------+
| user1 | user2 | dollar_share_user1 | dollar_share_user2 |
+-------+-------+--------------------+--------------------+
|     1 |     2 |                 50 |                350 |
|     3 |     1 |                100 |                200 |
|     1 |     3 |                150 |                150 |
|     3 |     1 |                100 |                300 |
+-------+-------+--------------------+--------------------+

ratings
+-------+-------+--------+
| user1 | user2 | rating |
+-------+-------+--------+
|     1 |     2 |      4 |
|     2 |     1 |      6 |
|     1 |     3 |      2 |
|     3 |     1 |      1 |
|     1 |     3 |      5 |
|     3 |     1 |      4 |
+-------+-------+--------+

我需要输出

output
+-----------------+---------------+--------------------+--------------+
| opponent_userID | opponent_name | delta_dollar_share | delta_ratings |
+-----------------+---------------+--------------------+--------------+
|               2 | beta          |               -300 |           -2 |
|               3 | gamma         |                300 |            2 |
+-----------------+---------------+--------------------+--------------+

where delta_dollar_share for 
 - beta: 50 - 350 = 300
 - gamma: (200+150+300) - (100+150+100) = 650 - 350 = 300
where delta_rating for
 - beta: 4 - 6 = -2
 - gamma: (2+5) - (1+4) = 2

我已经能够解决(有足够的困难)输出的各个组件。但我只是无法将它们全部合并到一个查询中。

-- get opponents
SELECT u1.userID, u1.name
FROM relationships r
    JOIN users u1
        ON (r.user2_userID = u1.userID)
WHERE (r.user1_userID = 1) AND (friendship = 1);


-- get delta_dollar_share for one opponent(gamma)
SELECT
    (CASE
        WHEN (user1 = 1) THEN SUM(dollar_share_user1)
        WHEN (user2 = 1) THEN SUM(dollar_share_user2)
    END) -
    (CASE
        WHEN (user1 = 3) THEN SUM(dollar_share_user1)
        WHEN (user2 = 3) THEN SUM(dollar_share_user2)
    END)
    AS delta_dollar_share
FROM games
WHERE
    ((user1 = 1) AND (user2 = 3)) OR 
    ((user1 = 3) AND (user2 = 1));


-- get delta_ratings for one opponent(gamma)
SELECT
SUM(CASE WHEN (user1 = 1) THEN rating END) - 
SUM(CASE WHEN (user1 = 3) THEN rating END) AS delta_ratings
FROM ratings
WHERE
    ((user1 = 1) AND (user2 = 3)) OR 
    ((user1 = 3) AND (user2 = 1));

请帮助我如何将所有这些组合成一个查询以获得所有对手所需的输出? SQL Fiddle here

1 个答案:

答案 0 :(得分:2)

我相信这就是你想要的。我已将您的第二和第三个查询与第一个查询相关联。我还将表达式更改为使用单个和来切换值的符号。

SELECT
    u.userID, u.name,
    (
    SELECT
        SUM(
            (gm.dollar_share_user1 - gm.dollar_share_user2) *        
            CASE when gm.user1 = r.user1_userID then 1 else -1 end
        )
    FROM games gm
    WHERE
            gm.user1 = r.user1_userID AND gm.user2 = r.user2_userID
        OR  gm.user1 = r.user2_userID AND gm.user2 = r.user1_userID
    ) AS delta_dollar_share,
    (
    SELECT
        SUM(rating * CASE when rt.user1 = r.user1_userID then 1 else -1 end)
    FROM ratings rt
    WHERE
            rt.user1 = r.user1_userID AND rt.user2 = r.user2_userID
        OR  rt.user1 = r.user2_userID AND rt.user2 = r.user1_userID
    ) AS delta_ratings
FROM
    relationships r INNER JOIN users u
        ON r.user2_userID = u.userID
WHERE
    r.user1_userID = ? AND r.friendship = 1; /* ? = 1 in your example */

工作样本:http://sqlfiddle.com/#!9/8fd7b/16

您实际上只是总结所有美元份额和评级值,只是当用户ID对应于用户1而其他用户的值被扣除时,您将其计为正数。因此,对于美元份额,其中一个总是正数而另一个是负数,这就是为什么它在括号内的差异操作。最终它仍然是全部添加,所以单个sum()就足够了,但你只需要根据case表达式的结果翻转符号。

我将额外的计算作为与r.user1_userIDr.user2_userID与外部查询相关联(相关)的子查询插入。