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