查询:获取每个成员的最后一条记录

时间:2013-01-04 21:30:32

标签: sql ruby sequel

给出一个表("表")如下(对于CSV样式很抱歉,因为我不知道如何使它看起来像使用Stack Overflow编辑器的表):

id,member,data,start,end
1,001,abc,12/1/2012,12/31/2999
2,001,def,1/1/2009,11/30/2012
3,002,ghi,1/1/2009,12/31/2999
4,003,jkl,1/1/2012,10/31/2012
5,003,mno,8/1/2011,12/31/2011

如果使用Ruby Sequel,我应该如何编写查询,以便获得以下数据集。

id,member,data,start,end
1,001,abc,12/1/2012,12/31/2999
3,002,ghi,1/1/2009,12/31/2999
4,003,jkl,1/1/2012,10/31/2012

我从原始表中获取EACH(不同)成员的最新(最大结束日期值)记录。

如果我将表转换为数组,我可以得到答案,但我正在寻找SQL或Ruby Sequel查询的解决方案,如果可能的话。谢谢。

额外的功劳:这篇文章的标题是蹩脚的...但我不能提出一个好的。如果你有一个,请提供更好的标题。谢谢。

3 个答案:

答案 0 :(得分:0)

结果的标准是什么?

如果是键1,3和4,您可以使用DB[:mytable].filter( :id => [1,3,4])(下面的完整示例)

有关使用续集过滤的详细信息,请参阅sequel documentation,尤其是Dataset Filtering

require 'csv'
require 'sequel'

#Create Test data     
DB = Sequel.sqlite()
DB.create_table(:mytable){
  field :id
  field :member
  field :data
  field :start #should be date, not implemented in example
  field :end   #should be date, not implemented in example
}
CSV.parse(<<xx
id,member,data,start,end
 1,001,abc,12/1/2012,12/31/2999
 2,001,def,1/1/2009,11/30/2012
 3,002,ghi,1/1/2009,12/31/2999
 4,003,jkl,1/1/2012,10/31/2012
 5,003,mno,8/1/2011,12/31/2011
xx
 ).each{|x|
  DB[:mytable].insert(*x)
}
#Create Test data - end -

puts DB[:mytable].filter( :id => [1,3,4]).all

答案 1 :(得分:0)

在我看来,你是从错误的一方接近问题。 ORM(和Sequel一样)代表了数据库上方一个不错的DSL-ish层,但是,在下面,它就是那里的所有SQL。所以,我会尝试以一种方式来表达问题和答案,以获得可以返回所需内容的SQL查询,然后看看它将如何转换为Sequel的语言。

您需要按成员分组并获取每个成员的最新记录,对吗?

我会按照以下想法(粗略地):

SELECT t1.*
FROM table t1
LEFT JOIN table t2 ON t1.member = t2.member AND t2.end > t1.end
WHERE t2.id IS NULL

现在你应该看看如何在续集中执行左连接,你也需要别名表。不应该那么难。

答案 2 :(得分:0)

续集版本有点吓人。我能想到的最好的方法是使用子选择,因为你需要将表和子选择连接在两列上,如Querying in Sequel中所述的“连接块”。以下是Knut程序的修改版本:

require 'csv'
require 'sequel'

# Create Test data     
DB = Sequel.sqlite()
DB.create_table(:mytable){
  field :id
  String :member
  String :data
  String :start # Treat as string to keep it simple
  String :end   # Ditto
}
CSV.parse(<<xx
  1,"001","abc","2012-12-01","2999-12-31"
  2,"001","def","2009-01-01","2012-11-30"
  3,"002","ghi","2009-01-01","2999-12-31"
  4,"003","jkl","2012-01-01","2012-10-31"
  5,"003","mno","2011-08-01","2011-12-31"
xx
).each{|x|
  DB[:mytable].insert(*x)
}

# That was all setup, here's the query
ds = DB[:mytable]
result = ds.join(ds.select_group(:member).select_append{max(:end).as(:end)}, :member=>:member) do |j, lj, js|
  Sequel.expr(Sequel.qualify(j, :end) => Sequel.qualify(lj, :end))
end
puts result.all

这会给你:

{:id=>1, :member=>"001", :data=>"abc", :start=>"2012-12-01", :end=>"2999-12-31"}
{:id=>3, :member=>"002", :data=>"ghi", :start=>"2009-01-01", :end=>"2999-12-31"}
{:id=>4, :member=>"003", :data=>"jkl", :start=>"2012-01-01", :end=>"2012-10-31"}

在这种情况下,用直接SQL替换最后四行可能更容易。类似的东西:

puts DB[
  "SELECT a.* from mytable as a 
  join (SELECT member, max(end) AS end FROM mytable GROUP BY member) as b 
  on a.member = b.member and a.end=b.end"].all

这会给你相同的结果。