【问题标题】:GROUP BY only primary key, but select other valuesGROUP BY 仅主键,但选择其他值
【发布时间】:2014-07-26 14:41:17
【问题描述】:

有没有办法按唯一(主)键进行分组,本质上隐含保证该表中的其他列将被明确定义?

SELECT myPrimaryKey, otherThing
FROM myTable
GROUP BY myPrimaryKey

我知道我可以将其他列添加到语句 (GROUP BY myPrimaryKey,otherThing),但我试图避免这种情况。如果你好奇为什么,请继续阅读:


我有一个声明基本上是这样做的:

SELECT nodes.node_id, nodes.node_label, COUNT(1)
FROM {a couple of joined tables}
INNER JOIN nodes USING (node_id)
GROUP BY nodes.node_id, nodes.node_label

这工作正常,但在 MySQL 中有点慢。如果我从GROUP BY 中删除nodes.node_label,它的运行速度大约快10 倍(根据EXPLAIN,这是因为早期的连接之一开始使用索引,而之前它没有使用)。

我们正在迁移到 Postgres,因此所有新语句都应该在可能的情况下与 both MySQL Postgres 兼容。现在在 Postgres 中,原来的语句运行得很快,但是新的语句(减少了 group by)不会运行(因为 Postgres 更严格)。在这种情况下,这是一个错误的错误,因为该语句实际上是明确定义的。

有没有一种我可以使用的语法,它可以让相同的语句在两个平台上运行,同时让 MySQL 只使用 group by 中的一列来提高速度?

【问题讨论】:

  • In this case, it's a false error because the statement is actually well-defined. 不不不,MySql 接受 GROUP BY 的怪异事物(结果不可预测),所有其他 DBMS 迫使您获得可预测的结果(这通常很有用)。为了找到解决方案,我宁愿在索引管理上工作,以避免 MySql 缓慢!
  • @RaphaëlAlthaus 通常是这样,但按主键(或任何 UNIQUE 键)分组可确保同一个表中的所有其他值都定义明确。
  • 但我怀疑这就是 dbms 的工作方式。我认为查询扫描和解析不会检查主键/唯一键。紧随其后的是(查询优化/执行策略)...
  • 顺便说一句,如果你这样做 select nodes.node_id, MIN(nodes.node_label), count(1)... GROUP BY nodes.node_id 会改变执行计划吗:这将被两个 dbms 接受?
  • PostgreSQL 从 9.1 postgresql.org/docs/current/static/release-9-1.html#AEN120856987654321@开始应该支持按主键分组

标签: mysql sql postgresql group-by


【解决方案1】:

您可以尝试将其他列转换为聚合:

SELECT myPrimaryKey, MAX(otherThing)
FROM myTable
GROUP BY myPrimaryKey

【讨论】:

  • 我喜欢这个技巧,我会暂时使用它。但正如 RichardHuxton 指出的那样,我正在寻找的行为在 Postgres 9.1+ 中是允许的,因此作为更持久的解决方案,我将要求更新测试数据库。
  • 当我只需要投影主键时应该做什么?
【解决方案2】:

在 Postgres 中(但不是在 MySQL 中),您可以使用 DISTINCT ON 为每个值(或一组值)选择一个单个一致的行,而无需聚合它们:

SELECT DISTINCT ON (n.node_id)
       *                 -- select any or all columns of all joined tables
FROM   {a couple of joined tables}
JOIN   nodes n USING (node_id)

这为每个node_id 提供了一个任意行。要选择特定行,请添加:

ORDER  BY n.node_id, ... -- what to sort first?

.. 添加更多 ORDER BY 项目以选择特定行。详情:
Select first row in each GROUP BY group?

【讨论】:

    【解决方案3】:

    在较新版本的 MySql 中,您可能启用了 sql_mode=only_full_group_by,这在使用 group by 时不允许选择非聚合列,即它会强制您使用像 max()avg() 或 @ 这样的函数987654327@,有时你只是想要任何价值。

    MySql 5.7 中默认启用此标志。

    any_value() 功能在启用该标志时可用。

    您可以在不禁用 ONLY_FULL_GROUP_BY 的情况下达到相同的效果 通过使用 ANY_VALUE() 来引用非聚合列。

    select t.index, any_value(t.insert_date)
    from my_table t
    group by t.index;
    

    更多信息在这里: https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by 和这里: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

    【讨论】:

      猜你喜欢
      • 2021-10-30
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多