Reputation: 1827
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 ?
Upvotes: 1
Views: 419
Reputation: 27855
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).
Upvotes: 2