【问题标题】:Combine 2 SELECTs into one SELECT in my RAILS application在我的 RAILS 应用程序中将 2 个 SELECT 合并为一个 SELECT
【发布时间】:2011-12-29 04:54:06
【问题描述】:

我有一个名为 ORDEREXECUTIONS 的表,其中存储了所有已执行的订单。这是一个多币种应用程序,因此该表有两列 CURRENCY1_ID 和 CURRENCY2_ID。

要获取特定货币对(例如欧元/美元)的所有订单列表,我需要逐行获取总数:

v = Orderexecution.where("is_master=1 and currency1_id=? and currency2_id=? and created_at>=?",c1,c2,Time.now()-24.hours).sum("quantity").to_d
v+= Orderexecution.where("is_master=1 and currency1_id=? and currency2_id=? and created_at>=?",c2,c1,Time.now()-24.hours).sum("unitprice*quantity").to_d

请注意,我的 SUM() 公式因货币顺序而异。 例如如果我想要货币对 USD 的总订购数量,则它会执行(假设 USD 的货币 ID 为 1,EUR 为 2。

v = Orderexecution.where("is_master=1 and currency1_id=? and currency2_id=? and created_at>=?",1,2,Time.now()-24.hours).sum("quantity").to_d
v+= Orderexecution.where("is_master=1 and currency1_id=? and currency2_id=? and created_at>=?",2,1,Time.now()-24.hours).sum("unitprice*quantity").to_d

如何在 RoR 中编写它,以便它只触发一条 SQL 语句到 MySQL?

【问题讨论】:

  • 2次查询中条件中c1,c2的顺序是不是故意的?
  • 是的,这是故意的。我不是将数据存储在数据库中的方式。 currency1_id 始终是买入货币,currency2_id 是卖出货币。我在一张桌子上存储买卖。

标签: mysql ruby-on-rails-3 performance


【解决方案1】:

我想这样可以:

v = Orderexecution.where("is_master=1 
                           and ( (currency1_id, currency2_id) = (?,?)
                              or (currency1_id, currency2_id) = (?,?)
                               )
                           and created_at>=?"
                        ,c1, c2, c2, c1, Time.now()-24.hours
                        )
                  .sum("CASE WHEN currency1_id=? 
                               THEN quantity 
                             ELSE unitprice*quantity 
                        END"
                      ,c1 
                      )
                  .to_d

【讨论】:

  • 完美运行。谢谢。只是一个小故障,我不得不将其更改为 v = Orderexecution.where("is_master=1 and ( (currency1_id, currency2_id) = (?,?) or (currency1_id, currency2_id) = (?,?) ) and created_at>= ?",c1, c2, c2, c1, Time.now()-24.hours).sum("CASE WHEN currency1_id=#{c1} THEN quantity ELSE unitprice*quantity END").to_d 我不太清楚为什么我必须更改 SUM 部分以使用 =#{c1} 而不是 =?但它一直给我一个错误。
  • 真的不知道,我的 Ruby 技能非常有限。只是试图将SQL翻译成它。说实话,在这种情况下,2 个查询似乎比 1 个更好。而且它们可能会更快。
  • 或者像SELECT (SELECT ...query1) + (SELECT ... query2)这样的东西。但是我不知道如何在 RoR 中编写(或者是否可能)。
【解决方案2】:

所以你可以这样做

SELECT SUM(IF(currency1_id = 1 and currency2_id = 2, quantity,0)) as quantity,
     SUM(IF(currency2_id = 1 and currency1_id = 2, unitprice * quantity,0)) as unitprice _quantity from order_expressions
WHERE created_at > ? and (currency1_id = 1 or currency1_id = 2)

如果你把它插入find_by_sql,你应该得到一个带有2个属性的对象,quantityunitprice_quantity(它们不会出现在控制台的inspect输出中,但如果您检查属性哈希或直接调用访问器方法)

但取决于您的索引,实际上可能会更慢,因为它可能无法有效地使用索引。 currency1_id 上看似多余的条件意味着这将能够使用 [currency1_id, created_at] 上的索引。在之前和之后进行基准测试 - 有时 2 个快速查询比 1 个慢查询要好!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-07
    • 2011-01-20
    • 2010-11-10
    • 2010-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    相关资源
    最近更新 更多