【问题标题】:PostgreSQL GROUP BY different from MySQL?PostgreSQL GROUP BY 与 MySQL 不同?
【发布时间】:2010-12-18 16:02:29
【问题描述】:

我一直在将一些 MySQL 查询迁移到 PostgreSQL 以使用 Heroku。我的大多数查询都可以正常工作,但是当我使用 group by 时,我总是遇到类似的重复错误:

错误:列“XYZ”必须出现在 GROUP BY 子句中或用于 聚合函数

谁能告诉我我做错了什么?


100% 运行的 MySQL:

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: ERROR: column “availables.id”必须出现在 GROUP BY 子句中或用于 聚合函数:
SELECT "availables".* FROM "availables" INNER 在 "rooms".id = "availables".room_id WHERE 上加入 "rooms" (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 查询):

+-----+-------+--------+------------+---------+---- ------------+---------------+ |编号 |价格 |斑点|预订日期 |房间号 | created_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排成套

【问题讨论】:

  • sooo... 使用 bookdate 上的 distinct 功能会更好吗?如果我这样做了,我还需要 group by 子句吗?
  • DISTINCTGROUP BY 慢。所以你应该小心,如果可能的话,更喜欢GROUP BY 解决方案。

标签: sql mysql ruby-on-rails postgresql heroku


【解决方案1】:

MySQL 的 GROUP BY 可以不用聚合函数(这与 SQL 标准相反),并且返回组中的第一行(我不知道基于什么条件),而 PostgreSQL 必须有聚合函数(MAX、SUM 等)在发出 GROUP BY 子句的列上。

【讨论】:

    【解决方案2】:

    如果我没记错的话,在 PostgreSQL 中,您必须添加从表中获取的每一列,其中 GROUP BY 子句应用 GROUP BY 子句。

    【讨论】:

      【解决方案3】:

      PostgreSQL 比 MySQL 更符合 SQL。输出中的所有字段(具有聚合函数的计算字段除外)都必须存在于 GROUP BY 子句中。

      【讨论】:

        【解决方案4】:

        正确,解决此问题的解决方案是使用 :select 并选择您希望用来装饰结果对象的每个字段并按它们分组。

        讨厌 - 但它是 group by 应该 的工作方式,而不是 MySQL 如何通过猜测如果你不将字段粘贴到 group by 中的意思来处理它。

        【讨论】:

        • 我想 MySQL 已经宠坏了我,或者毁了我,无论你喜欢哪个形容词,所以没有更好的方法吗? IE。加入一个聚合函数,如 MAX(bookdate) 或 DISTINCT,我在上面被告知要慢得多?
        • 我会坚持使用 group by - 但要小心行事,特别是因为您必须手动选择要用来装饰对象的字段。此外,使用 group by 编写手动选择是一种与数据库无关的方法,考虑到 MSSQL(如果您不幸不得不使用它)和 Oracle 也会以类似的方式抱怨。
        • DISTINCT 并不一定意味着更慢。
        【解决方案5】:

        MySQL 完全不符合标准的GROUP BY 可以被Postgres 的DISTINCT ON 模拟。考虑一下:

        MySQL:

        SELECT a,b,c,d,e FROM table GROUP BY a
        

        这会为每个 a 的值提供 1 行(您不知道是哪一行)。实际上你可以猜到,因为 MySQL 不知道散列聚合,所以它可能会使用排序...但它只会在 a 上排序,所以行的顺序可能是随机的。除非它使用多列索引而不是排序。好吧,无论如何,它不是由查询指定的。

        Postgres:

        SELECT DISTINCT ON (a) a,b,c,d,e FROM table ORDER BY a,b,c
        

        这为a 的每个值提供 1 行,该行将是根据查询指定的 ORDER BY 排序的第一行。很简单。

        请注意,这里不是我计算的聚合。所以GROUP BY 实际上没有任何意义。 DISTINCT ON 更有意义。

        Rails 与 MySQL 结合,所以我对它生成的 SQL 在 Postgres 中不起作用并不感到惊讶。

        【讨论】:

        • 此外,如果表的主键是 group by 子句的一部分,Postgres 9.1 允许不列出所有列。
        • 根据this article "Debunking GROUP BY myths"的说法,与“不符合标准的GROUP BY”无关。
        • 根据这篇文章,MySQL 的 GROUP BY 仍然不符合这两个版本的标准,因为它不会验证 selectlist 中的额外列是否依赖于 group by 列。它会在没有警告的情况下输出不正确的数据(但也可以用于有用的目的)。 PG 9.1 假设包含表的 PK 意味着所有其他列都是依赖的,这是正确的。这不涵盖标准的 100%(其他正确的查询可能会被标记为错误),但涵盖了大多数用例而不会返回不正确的结果...
        • “Rails 与 MySQL 结合,所以我并不惊讶它生成的 SQL 在 postgres 中不起作用。”我认为这不再是真的了,因为 Postgres 因其 noSQL 功能而在 Rails 社区中变得非常流行。
        • Rails 不再与 MySQL 结婚。
        【解决方案6】:

        根据 MySQL 的“Debuking GROUP BY Myths”http://dev.mysql.com/tech-resources/articles/debunking-group-by-myths.html。 SQL(标准的 2003 版)不要求查询的 SELECT 列表中引用的列也出现在 GROUP BY 子句中。

        【讨论】:

        • 但是,正如其他人指出的那样,它确实要求它们“在功能上依赖于”GROUP BY 的列。 MySQL 引用 any 非分组列的能力完全是非标准的,并且允许用户编写不合逻辑和不可靠的查询。
        • 当时这是一个标准,所以它不是“完全不标准”。我支持你,但这将是我们的意见。
        • 什么时候?链接的文章(通过 Wayback 或 alt URL)说 SQL:1999 和 SQL:2003 都对 MySQL 忽略的 GROUP BY 施加了限制。
        【解决方案7】:

        我认为 .uniq [1] 将解决您的问题。

        [1] Available.select('...').uniq
        

        看看http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields

        【讨论】:

          【解决方案8】:

          不是最漂亮的解决方案,但更改 group 参数以输出模型中的每一列在 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')
          

          【讨论】:

            【解决方案9】:

            对于在 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")
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-05-11
              • 2017-08-24
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-02-25
              相关资源
              最近更新 更多