我在Heroku运行了一个Rails应用程序,我正在尝试计算用户在高分列表中的排名(位置)。
应用程序是用户互相下注的地方,可以开始下注(创建选项)或者他们可以对已经创建的选项下注(通过下注)。
我有以下SQL,它应该根据他们在选择和投注上的总奖金给我一系列用户..但是它给了我一些错误的总胜利,我认为问题在于左连接,因为如果我重写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 |
+---------------+
答案 0 :(得分:1)
这是因为两个LEFT JOIN
ed表之间的关系 - 也就是说,如果bets
和choices
中都有(多个)行,则总行数会发生看到的是从单个行数中乘以,而不是加法
如果你有
choices
id profitloss
================
1 20
1 30
bets
id profitloss
================
1 25
1 35
联接的结果实际上是:
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
(另外,我认为惯例是命名表单数,而不是复数。)
答案 1 :(得分: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
答案 2 :(得分:0)
在与发条相似的解决方案中,由于每个表的列是相同的,我会将它们预先合并,然后将它们相加。因此,在大多数情况下,内部查询将为每个用户提供两个记录...一个用于下注,一个用于选择 - 每个分别在执行UNION ALL时预先求和。然后,简单的join / sum来获得结果
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