【问题标题】:selecting a variable amount of records based on the sum of columns values根据列值的总和选择可变数量的记录
【发布时间】:2014-05-25 17:14:57
【问题描述】:

我有一个表格,其中有一列是浮动的。 我通过 created_at 订购表格: Foo.order(:created_at)

我想从该有序表中选择可变数量的记录。

它是多种多样的,因为我需要对记录中浮点列的值求和,以获得大于目标浮点的值。

假设我在上面订购了我的表,它有这 4 条记录,以及它们的浮点值:

  1. 30
  2. 50
  3. 40
  4. 20

如果我的目标浮点数是 60,我只想返回前 2 条记录 如果我的目标浮点数是 100,我想返回 3 条记录 如果我的目标浮点数是 20,我只想要第一条记录

有没有办法在活动记录或直接 sql 中做到这一点?

这样做会更快,还是我应该查询所有记录并只使用我需要的记录?

编辑:

基于该问题,我想从已按其中一列首先排序的表中进行选择,比如说 fizz:

select foo1.id, 
    (select coalesce(sum(f2.amount),0) 
     from (select * from foo order by fizz) f2 
     where f2.id < f1.id) as amount_total 
from (select * from foo order by fizz)
group by f1.id
having amount_total < target_total

这可行,但并不理想,因为您要订购两次餐桌。有没有办法一次性订购表格,然后将其用于 f1 和 f2?

【问题讨论】:

    标签: sql ruby-on-rails performance


    【解决方案1】:

    假设表foo 具有idbarfizz 列:

    id bar fizz
    -- --- ----
    1  30  3
    2  50  2
    3  40  1
    4  20  4
    

    您可以在 SQL 中执行此操作,但我认为您无法在 ActiveRecord 中执行此操作。

    select f1.id, f1.bar, f1.fizz, 
           (select coalesce(sum(f2.bar),0) 
              from foo f2 
             where f2.fizz < f1.fizz) as bar_total 
      from foo f1 
     group by f1.id, f1.bar, f1.fizz
    having bar_total < TEST_VALUE
     order by f1.fizz;
    

    注意:正如下面的 cmets 所指出的,您可能需要也可能不需要 group by 子句。 sqlite3 需要它,但 mysql 不需要。

    例如,如果 TEST_VALUE = 60:

    id bar fizz bar_total
    -- --- ---- -------------
    3  40  1    0
    2  50  2    40
    

    如果 TEST_VALUE = 100:

    id bar fizz bar_total
    -- --- ---- -------------
    3  40  1    0
    2  50  2    40
    1  30  3    90
    

    如果 TEST_VALUE = 20:

    id bar fizz bar_total
    -- --- ---- -------------
    3  40  1    0
    

    【讨论】:

    • 我使用“sqlite3 db/development.sqlite3”连接到我的 sqlite3 数据库,最终工作的查询是“select foo1.id, (select coalesce(sum(f2.amount),0) from foo f2 where f2.id
    • @user2761764 - 谢谢 :) 我不确定你使用的是什么数据库 - 我最初是在 mysql 上工作的,但我只是在 sqlite 上尝试过,得到了同样的错误。我现在修改了我的答案,加入了group by 子句。
    • 基于该问题,我想从已按其中一个列首先排序的表中进行选择,可以说 fizz:select foo1.id, (select coalesce(sum(f2.amount),0 ) from (select * from foo order by fizz) f2 where f2.id
    • 这能满足您的需求吗?它只按 fizz 排序一次,并通过比较 fizz 的值而不是 id 将运行总计的构建更改为该排序。
    • 我试了一下,它看起来不错,谢谢,你的头正中。
    【解决方案2】:

    也许可以这样做:

    def check_sum(target)
       if target == 60.00
         return Foo.order(:created_at).limit(2)
       elsif target == 100.00
         return Foo.order(:created_at).limit(3)
       elsif target == 20.00
         return Foo.order(:created_at).limit(1)
       end
    end
    

    你也可以按ASC/DESC排序例子Foo.order("created_at DESC")

    【讨论】:

    • 这不是我真正想要的,id 喜欢在 sql 中的限制逻辑,而不是 ruby​​。加上你所做的对不同的值不起作用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-01
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多