当对象可能为 Nil 时求和
Posted
技术标签:
【中文标题】当对象可能为 Nil 时求和【英文标题】:Sum when object might be Nil 【发布时间】:2012-10-30 15:17:19 【问题描述】:我有以下代码行:
@ranking_array = User.joins(:bets, :choices).select("users.id, sum(bets.profitloss + choices.profitloss) as total_pl").group("users.id").order("total_pl DESC").map(&:id)
这给了我一个用户排名的数组——比如用户 X 排在第 25 位,依此类推。
但问题是,如果用户没有对任何选择下注,则结果将不包括该用户。
那么如何修复代码,即使选择的任何一个赌注都是零,它也会总结利润损失。
解决方案:
嗯.. 看来我必须结合你的两个答案才能使它起作用:)
我需要LEFT JOIN
和COALESCE
,所以我得到了以下似乎可以工作的代码..
@ranking_array = User.find(:all,
:joins => "LEFT JOIN `bets` ON bets.user_id = users.id LEFT JOIN `choices`ON choices.user_id = users.id",
:select => "users.id, sum(COALESCE(bets.profitloss, 0) + COALESCE(choices.profitloss, 0)) as total_pl",
:group => "users.id",
:order => "total_pl DESC").map(&:id)
非常感谢..我已经用了一整天的时间来解决这个问题..
问题是谁得到答案现在这是两者的结合?
【问题讨论】:
您可以注入一个 if 语句将任何空值转换为零,以确保总和中的计数。因为加零不会改变总数。 【参考方案1】:我有一天也不得不使用这个,比如查看 COALESCE(something, 0) 它将返回一个或另一个。我认为你可以在 0 之前添加更多选项,因为它会一直持续到 0。
@ranking_array = User.joins(:bets, :choices).select("users.id, sum(COALESCE(bets.profitloss, 0) + COALESCE(choices.profitloss, 0)) as total_pl").group("users.id").order("total_pl DESC").map(&:id)
【讨论】:
这个解决方案不是 db-agnostic,而是工作,除了INNER JOIN
【参考方案2】:
我自己不使用 Ruby,但您说您“缺少”未进行任何“下注”的用户的行。听起来您的实际查询正在生成一个INNER JOIN
,而您需要一个LEFT JOIN
。看看有没有this SO answer helps。
【讨论】:
当心!请记住,向NULL
添加一些内容会得到NULL
。因此,如果您有未定义的字段,则必须强制转换值(请参阅@pjammer 的解决方案)
Bob Duell:LEFT JOIN 效果更好。 @m_x:没有强制转换,只有使用 LEFT JOIN,mysql 和 Oracle 在玩家有空值时给出总计或空值。例如x 在记录中有历史投注,但昨天/今天他的投注无效。 y 根本没有赌注,所以全部为空。使用 LEFT JOIN,它返回 x = 20, y = (null) 。所以我很好奇你是否用“未定义”表示其他意思,因为在这个 (x,y) 示例中已经存在“未定义”字段。
我不确定我明白你的意思,我只想说如果你想做x+y,你必须做coalesce(x,0)+coalesce(y,0 ) .给出你的例子,如果你做 20+null,你的结果是 null,而不是 20。以上是关于当对象可能为 Nil 时求和的主要内容,如果未能解决你的问题,请参考以下文章