PostgreSQL GROUP BY与MySQL不同?
我一直在迁移一些MySQL查询到PostgreSQL来使用Heroku。 我的大部分查询都能正常工作,但是当我使用group时,我仍然遇到类似的重复性错误:
错误:列“XYZ”必须出现在GROUP BY子句中或用于聚合函数中
有人能告诉我我做错了什么吗?
MySQL的工作100%:
SELECT `availables`.* FROM `availables` INNER JOIN `rooms` ON `rooms`.id = `availables`.room_id WHERE (rooms.hotel_id = 5056 AND availables.bookdate BETWEEN '2009-11-22' AND '2009-11-24') GROUP BY availables.bookdate ORDER BY availables.updated_at
PostgreSQL错误:
ActiveRecord :: StatementInvalid:PGError:错误:列“availables.id”必须出现在GROUP BY子句中或用于聚合函数中:
SELECT“availables”。* FROM“availables”INNER JOIN“rooms”ON“rooms”.id =“availables”.room_id WHERE(rooms.hotel_id = 5056 AND availables.bookdate BETWEEN E'2009-10-21'AND E' 2009-10-23')GROUP BY availables.bookdate ORDER BY availables.updated_at
生成SQL的Ruby代码:
expiration = Available.find(:all, :joins => [ :room ], :conditions => [ "rooms.hotel_id = ? AND availables.bookdate BETWEEN ? AND ?", hostel_id, date.to_s, (date+days-1).to_s ], :group => 'availables.bookdate', :order => 'availables.updated_at')
预期输出(来自正在运行的MySQL查询):
+ ----- + ------- ------- + ------------ + + --------- + ---- ----------- + --------------- + | id | 价格| 点| | bookdate | room_id | created_at | updated_at | + ----- + ------- ------- + ------------ + + --------- + ---- ----------- + --------------- + | 414 | 38.0 | 1 | 2009-11-22 | 1762 | 2009-11-20 ... | 2009-11-20 ... | | 415 | 38.0 | 1 | 2009-11-23 | 1762 | 2009-11-20 ... | 2009-11-20 ... | | 416 | 38.0 | 2 | 2009-11-24 | 1762 | 2009-11-20 ... | 2009-11-20 ... | + ----- + ------- ------- + ------------ + + --------- + ---- ----------- + --------------- + 设置3行
MySQL的完全不符合标准的GROUP BY可以被Postgres的DISTINCT ON模拟。 考虑这个 :
mysql:
SELECT a,b,c,d,e FROM table GROUP BY a
这提供了每行1个值(哪一个,你不知道)。 实际上,你可以猜测,因为MySQL不知道哈希聚合,所以它可能会使用sorting…但它只会sorting在一个,所以行的顺序可能是随机的。 除非它使用多列索引而不是sorting。 好吧,无论如何,这不是查询指定的。
postgres:
SELECT DISTINCT ON (a) a,b,c,d,e FROM table ORDER BY a,b,c
这为每个a值提供了1行,这个行将是根据查询指定的ORDER BYsorting的第一个行。 简单。
请注意,在这里,这不是我计算的总和。 所以GROUP BY实际上是没有意义的。 DISTINCT ON更有意义。
Rails和MySQL结婚,所以我不惊讶它生成的SQL在postgres中不起作用。
PostgreSQL比MySQL更符合SQL。 输出中的所有字段(包含聚合函数的计算字段除外)必须存在于GROUP BY子句中。
MySQL的GROUP BY可以在没有聚合函数的情况下使用(这与SQL标准相反),并返回组中的第一行(我不知道基于什么标准),而PostgreSQL必须具有聚合函数(MAX, SUM等),在其上发出GROUP BY子句。
正确的,解决这个问题的方法是使用:select和select来select你想要装饰的结果对象。
讨厌的 – 但它是如何工作,而不是MySQL的工作方式,通过猜测你的意思,如果你不坚持领域在你的小组。
如果我没有记错,在PostgreSQL中,你必须添加从GROUP BY子句适用于 GROUP BY子句的表中获取的每一列。
不是最漂亮的解决scheme,而是改变组参数来输出PostgreSQL模型中的每一列:
expiration = Available.find(:all, :joins => [ :room ], :conditions => [ "rooms.hotel_id = ? AND availables.bookdate BETWEEN ? AND ?", hostel_id, date.to_s, (date+days-1).to_s ], :group => Available.column_names.collect{|col| "availables.#{col}"}, :order => 'availables.updated_at')
根据MySQL的“Debuking GROUP BY Myths” http://dev.mysql.com/tech-resources/articles/debunking-group-by-myths.html 。 SQL(标准的2003版本)不要求查询的SELECT列表中引用的列也出现在GROUP BY子句中。
对于其他寻找一种方法来定购的任何领域,包括join领域,在postgresql,使用子查询:
SELECT * FROM( SELECT DISTINCT ON(availables.bookdate) `availables`.* FROM `availables` INNER JOIN `rooms` ON `rooms`.id = `availables`.room_id WHERE (rooms.hotel_id = 5056 AND availables.bookdate BETWEEN '2009-11-22' AND '2009-11-24') ) AS distinct_selected ORDER BY availables.updated_at or arel: subquery = SomeRecord.select("distinct on(xx.id) xx.*, jointable.order_field") .where("").joins(") result = SomeRecord.select("*").from("(#{subquery.to_sql}) AS distinct_selected").order(" xx.order_field ASC, jointable.order_field ASC")
我认为.uniq [1]将解决您的问题。
[1] Available.select('...').uniq
看看http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields