简体   繁体   中英

Executing raw query ruby on rails

I want to execute de following query:

query = "select v.price, v.quantity, p.title, v.product_id from variants v join products p on (v.product_id = p.id) where (v.price,v.product_id) in (select min(price),product_id from variants group by product_id);"

When I do results = ActiveRecord::Base.connection.execute(query) in the rails console I get:

 ActiveRecord::StatementInvalid: SQLite3::SQLException: near ",": syntax error: select v.price, v.quantity, p.title, v.product_id from variants v join products p on (v.product_id = p.id) where (v.price,v.product_id) in (select min(price),product_id from variants group by product_id)

I am sure that all the commas are in place and the statement is pretty well written at least for Oracle . Where is my mistake ?

It seems sqlite3 doesn't supper th in-operator with multiple values ( where (v.price,v.product_id) in (select min(price),product_id... )

From discussion the question behind is:

I need to get the lowest price(it's in Variants) of every product along with the name(it's in Products) and quantity(it's in Variants)

Based on this I recommend this SQL-statement:

SELECT min(`v`.`price`) AS 'min_price', `v`.`quantity`, `p`.`title`, `v`.`product_id` FROM `variants` AS 'v' INNER JOIN `products` AS 'p' ON (`v`.`product_id` = `p`.`id`) GROUP BY `product_id`

or same statement in a human readable version:

SELECT 
  min(`v`.`price`) AS 'min_price', 
  `v`.`quantity`, `p`.`title`, `v`.`product_id`
FROM `variants` AS 'v' 
INNER JOIN `products` AS 'p' 
  ON (`v`.`product_id` = `p`.`id`) 
GROUP BY `product_id`

I don't use rails and active record, I used sequel to get this solution. Here is my complete script to test the code:

require 'sequel'

DB = Sequel.sqlite('test.db')
Sequel.extension :core_extensions
Sequel.extension :pretty_table

#if called 2nd time with a db-file
DB.drop_table(:variants) if DB.table_exists?(:variants)
DB.drop_table(:products) if DB.table_exists?(:products)

DB.create_table :products do |t| 
  primary_key :id
  t.string :title 
  t.string :description 
  t.timestamps null: false 
end 
DB.create_table :variants do |t| 
  primary_key :id
  t.boolean :is_active 
  t.integer :price 
  t.integer :quantity 
  t.timestamps null: false 

  foreign_key :product_id, :products
end 

class Product < Sequel::Model; end
class Variant < Sequel::Model; end

10.times do |g| 
  Product.create(title: "Prod %02i" % g, description: "Who Cares..") 
end 

 100.times do |c| 
   Variant.create(
    price: (rand(100)).ceil, quantity: (rand(10).ceil).floor , 
    product_id: Product[rand(1..10).floor].id
   ) 
 end

puts DB.tables

sel = DB[:variants.as(:v)]
  .select(Sequel.function(:min,:v__price).as(:min_price), :v__quantity, :p__title, :v__product_id)
  .join(:products.as(:p), :v__product_id => :p__id)
  .group_by(:product_id)

puts sel.sql

Sequel::PrettyTable.print(sel)

The result is:

SELECT min(`v`.`price`) AS 'min_price', `v`.`quantity`, `p`.`title`, `v`.`product_id` FROM `variants` AS 'v' INNER JOIN `products` AS 'p' ON (`v`.`product_id` = `p`.`id`) GROUP BY `product_id`
+---------+----------+--------+-------+
|min_price|product_id|quantity|title  |
+---------+----------+--------+-------+
|        1|         1|       5|Prod 00|
|       12|         2|       9|Prod 01|
|       21|         3|       6|Prod 02|
|        1|         4|       0|Prod 03|
|       34|         5|       8|Prod 04|
|       11|         6|       8|Prod 05|
|       14|         7|       9|Prod 06|
|        7|         8|       8|Prod 07|
|       11|         9|       8|Prod 08|
|       21|        10|       8|Prod 09|
+---------+----------+--------+-------+

(Values may differ for your execution, there are random values in the data creation).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM