Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return hash with multiple key/value pairs from raw sql query

I'm building a ruby on rails application that uses raw SQL to query my database.

Lets say for simplicity’s sake, I have the following records in Table1:

<date:"2020-06-09 23:10:00", pid: 1, price: 5, tax: 0.65, shipping: 10>
<date:"2020-06-09 13:00:00", pid: 1, price: 10, tax: 1.3, shipping: 12>
<date:"2020-06-10 10:00:00", pid: 2, price: 20, tax: 2.6, shipping: 11>
<date:"2020-06-10 11:00:00", pid: 3, price: 5, tax: 0.65, shipping: 13>

My query is supposed to return a hash where each key represents a day, and the values would be the count of unique pid and a summation of the rest of the values. So the response in this case would be:

{
   2020-06-09: {
      pid_count: 1,
      price: 15,
      tax: 1.95,
      shipping: 22
   },
   2020-06-10: {
      pid_count: 2,
      price: 25,
      tax: 3.25,
      shipping: 24
   }
}

My query is:

query = <<-SQL
  SELECT TO_CHAR(TO_TIMESTAMP(table1.date), 'YYYY-MM-DD'), COUNT(DISTINCT table1.pid) as pid_count,
  sum(table1.price) as price, sum(table1.tax) as tax, sum(table1.shipping) as shipping from table1
  group by TO_CHAR(TO_TIMESTAMP(table1.date), 'YYYY-MM-DD')
SQL
results = ActiveRecord::Base.connection.execute(query).values

The calculation is correct but the problem is this doesn't group them properly into a hash. Calling .to_h on results gives an error ArgumentError (wrong array length at 0 (expected 2, was 5))

like image 687
jim Avatar asked Jan 29 '26 20:01

jim


1 Answers

The reason you can't call to_h is because the method is expecting the structure:

[
  [key, value],
  [key, value],
  # ...
]

whereas you have the structure:

[
  [value_1, value_2, value_3, value_4, value_5],
  [value_1, value_2, value_3, value_4, value_5],
  # ...
]

To correctly convert it into the structure you want you have to tell to_h how to do so by providing a block.

column_names = %i[pid_count price tax shipping]
hash = results.to_h { |date, *values| [date, column_names.zip(values).to_h] }

This tells the to_h call to use the date as key, then zip the column names with the other values and convert them to a hash and use them as value.

The above might solve the issue, but in most cases there is no need to use execute to start with. Assuming table1 has a model I'd recommend using model methods instead like group and select/pluck. Those can be given SQL or Arel for more complex queries.

like image 179
3limin4t0r Avatar answered Jan 31 '26 12:01

3limin4t0r



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!