1

我有一个在 Heroku 运行的 Rails 应用程序,我正在尝试计算用户在高分列表中的排名(位置)。

该应用程序是用户相互下注的地方,可以开始下注(创建一个选择),或者他们可以对一个已经创建的选择下注(通过下注)。

我有以下SQL,它应该根据他们在Choices 和Bets 上的总奖金给我一个用户数组。但它给了我一些错误的总奖金,我认为问题出在Left Joins 因为如果我将SQL 重写为只包含 Choice 或 Bet 表,然后我就可以正常工作了..

任何人都知道如何重写 SQL 以使其正常工作:)

SELECT users.id, sum(COALESCE(bets.profitloss, 0) + COALESCE(choices.profitloss, 0)) as total_pl
FROM users
LEFT JOIN bets ON bets.user_id = users.id
LEFT JOIN choices ON choices.user_id = users.id
GROUP BY users.id
ORDER BY total_pl DESC

结果:

+---------------+
| id | total_pl |
+---------------+
|  1 |      830 |
|  4 |      200 |
|  3 |      130 |
|  7 |     -220 |
|  5 |    -1360 |
|  6 |    -4950 |
+---------------+

下面是我只连接到一个表的两个 SQL 字符串以及来自该表的两个结果.. 看到下面的总和与上面的结果不匹配.. 下面是正确的总和。

SELECT users.id, sum(COALESCE(bets.profitloss, 0)) as total_pl 
FROM users 
LEFT JOIN bets ON bets.user_id = users.id 
GROUP BY users.id 
ORDER BY total_pl DESC

SELECT users.id, sum(COALESCE(choices.profitloss, 0)) as total_pl 
FROM users 
LEFT JOIN choices ON choices.user_id = users.id 
GROUP BY users.id 
ORDER BY total_pl DESC

+---------------+
| id | total_pl | 
+---------------+
|  3 |      170 |
|  1 |      150 |
|  4 |      100 |
|  5 |       80 |
|  7 |       20 |
|  6 |      -30 |
+---------------+

+---------------+
| id | total_pl |
+---------------+
|  1 |       20 |
|  4 |        0 |
|  3 |      -10 |
|  7 |      -30 |
|  5 |     -110 |
|  6 |     -360 |
+---------------+
4

3 回答 3

1

发生这种情况是因为两个 ed 表之间的关系- 也就是说,如果和LEFT JOIN中都有(多)行,则看到的总行数是从各个行数乘以,而不是相加。 如果你有betschoices

choices
id   profitloss
================
1    20
1    30

bets
id   profitloss
================
1    25
1    35

join的结果其实是:

bets/choices
id   bets.profitloss   choices.profitloss
1    20                25
1    20                35
1    30                25
1    30                35

(看看这是怎么回事?)

解决这个问题实际上相当简单。您尚未指定 RDBMS,但这应该适用于其中任何一个(或稍作调整)。

SELECT users.id, COALESCE(bets.profitloss, 0) 
                     + COALESCE(choices.profitloss, 0) as total_pl
FROM users
LEFT JOIN (SELECT user_id, SUM(profitloss) as profitloss
           FROM bets
           GROUP BY user_id) bets
ON bets.user_id = users.id
LEFT JOIN (SELECT user_id, SUM(profitloss) as profitloss
           FROM choices
           GROUP BY user_id) choices
ON choices.user_id = users.id
ORDER BY total_pl DESC

(另外,我相信惯例是将表命名为单数,而不是复数。)

于 2012-11-30T19:46:37.613 回答
1

您的问题是您正在破坏您的数据集。如果您执行了 SELECT *,您将能够看到它。试试这个。我无法测试它,因为我没有你的桌子,但它应该可以工作

SELECT
 totals.id
 ,SUM(totals.total_pl) total_pl
FROM
(
  SELECT users.id, sum(COALESCE(bets.profitloss, 0)) as total_pl 
  FROM users 
  LEFT JOIN bets ON bets.user_id = users.id 
  GROUP BY users.id 

  UNION ALL SELECT users.id, sum(COALESCE(choices.profitloss, 0)) as total_pl 
  FROM users 
  LEFT JOIN choices ON choices.user_id = users.id 
  GROUP BY users.id 
 ) totals
GROUP BY  totals.id
ORDER BY total_pl DESC
于 2012-11-30T19:52:19.757 回答
0

在与 Clockwork 类似的解决方案中,由于每个表的列相同,因此我会将它们预先联合起来并求和。因此,在大多数情况下,内部查询将为每个用户提供两条记录……一条用于赌注,一条用于选择——每条记录都是在执行 UNION ALL 后分别预先求和的。然后,简单的加入/求和得到结果

select 
      U.userid,
      sum( coalesce( PreSum.profit, 0) ) as TotalPL
   from
      Users U
         LEFT JOIN
            ( select user_id, sum( profitloss ) as Profit
                 from bets
                 group by user_id
              UNION ALL
              select user_id, sum( profitloss ) as Profit
                 from choices
                 group by user_id ) PreSum
            on U.ID = PreSum.User_ID
   group by
      U.ID
于 2012-11-30T19:57:27.297 回答