質問

I can run any SQL, and get the results as a hash of columns, or rather a set of Postgres tuples (containing a hash for each tuple).

I am unsure how to work with the Postgres result set, especially in an idiomatic Ruby-like way.

This is my code:

sql = "select status, count(*) from batch_details where batch_id = 950 group by status"
status_counts = ActiveRecord::Base.connection.execute(sql)

I have to iterate though the result set and access each element by name:

status_counts.each do |st|
  puts st
  puts st['count']
end

{"status"=>"new", "count"=>"2"}
2
{"status"=>"ready", "count"=>"23"}
23
{"status"=>"processing", "count"=>"177"}
177
{"status"=>"complete", "count"=>"50"}
50
{"status"=>"error", "count"=>"50"}
50

It is not possible to convert the result set to an array of hashes:

2.1.1 :031 > arr = status_counts.to_array
NoMethodError: undefined method `to_array' for #<PG::Result:0x000000097f17b0>

Same thing trying to convert the result set to a hash of hashes:

2.1.1 :032 > hsh = status_counts.to_hash
NoMethodError: undefined method `to_hash' for #<PG::Result:0x000000097f17b0>

I am trying to:

  • run a grouped by query against a (large) db
  • determine a % processing completed by excluding some values

Using the hashes above, I would like to exclude the 'new' and 'ready' statuses and add up the rest then divide by the total:

(177 + 50 + 50 / 2 + 23 + 177 + 50 + 50) * 100

My code so far:

status_counts.each {|st| total += st['count'].to_i} => works

But it doesn't work:

status_counts.each do |st|
  ['processing','complete','error'].include? st['status'] do
       total2 += st['count'].to_i
   end
end

pct = total2/total * 100
  • How can I work with the Postgres result sets more easily?
  • How can I do this task in the "Ruby way"?
役に立ちましたか?

解決

Perhaps something like this?:

status_counts.
  select { |tuple| %w(processing complete error).include?(tuple['status']) }.
  inject(0) { |memo, tuple| memo += tuple['count'].to_i }

The first step filters the result set to obtain the desired tuples; the second step sums up the counts from the selected tuples. PGResult mixes in Enumerable, so it should work with select/inject.

他のヒント

Not an exact answer to my own question, but useful information for anyone trying to iterate a Postgres result set:

sql = "update batch_details set status = 'processing' " +
      "where status in ('ready','processing','failed') " +
      "and batch_id = #{batch_id} " +
      "returning id"
batch_detail_ids = []
res = ActiveRecord::Base.connection.execute(sql)   
# TODO needs some error checking  
res.each{|tuple| batch_detail_ids << tuple['id'].to_i}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top