在rails上执行原始查询ruby

时间:2015-05-23 17:07:08

标签: sql ruby-on-rails ruby activerecord

我想执行以下查询:

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);"

当我在rails控制台中results = ActiveRecord::Base.connection.execute(query)时,我得到:

 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)

我确信所有的逗号都已到位,并且该语句至少对Oracle来说非常好。我的错误在哪里?

1 个答案:

答案 0 :(得分:2)

似乎sqlite3没有超过运算符的多个值(where (v.price,v.product_id) in (select min(price),product_id...

通过讨论背后的问题是:

  

我需要获得每种产品的最低价格(在Variants中)   名称(在产品中)和数量(在变体中)

基于此,我推荐这个SQL语句:

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`

或人类可读版本中的相同陈述:

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`

我不使用rails和活动记录,我使用续集来获得此解决方案。这是我测试代码的完整脚本:

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)

结果是:

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|
+---------+----------+--------+-------+

(执行时的值可能不同,数据创建中有随机值)。