【问题标题】:Selecting columns in Postgres that aren't in GROUP BY?在 Postgres 中选择不在 GROUP BY 中的列?
【发布时间】:2017-02-06 16:55:19
【问题描述】:

所以我一直在使用以下命令的 sqlite3 工作:

select origin_city, dest_city, actual_time 
FROM flights 
GROUP BY origin_city 
ORDER BY actual_time desc;

但是当尝试在 psql 中执行此操作时,它不喜欢 dest_city 和 actual_time 不在 GROUP BY 子句中。我正在尝试从每个出发地选择最长的航班并显示出发地、目的地和飞行时间。我该如何解决这个问题?

【问题讨论】:

  • 通过将它们添加到组中或在它们上使用诸如 max 之类的聚合函数
  • 你想做什么?这种说法毫无意义。
  • @a_horse_with_no_name 从每个出发地选择最长的航班并显示出发地、目的地和飞行时间

标签: sql postgresql greatest-n-per-group


【解决方案1】:

根据您更新的问题,您可以使用row_number 窗口函数将最长的航班标记为1,依此类推,然后过滤最上面一行:

select origin_city, dest_city, actual_time
from (
  select
    t.*,
    row_number() over (partition by origin_city order by actual_time desc) rn
  from flights t
) t where rn = 1;

【讨论】:

    【解决方案2】:

    为什么现在创建一个临时表来保存每个 origin_city 的最大实际时间?

    SELECT temp.origin_city, flights.dest_city, temp.actual_time 
    FROM (
      SELECT origin_city, MAX(actual_time) actual_time 
      FROM flights 
      GROUP BY origin_city 
    ) temp
    JOIN flights using (origin_city, actual_time)
    ORDER BY temp.actual_time DESC
    

    【讨论】:

      【解决方案3】:

      您可以在 cte 或子查询中为此使用 ROW_NUMBER() 函数:

      WITH cte as (SELECT *
                          ,ROW_NUMBER() OVER(PARTITION BY origin_city ORDER BY actual_time DESC) RN 
                    FROM flights
                   )
      SELECT origin_city, dest_city, actual_time 
      FROM cte
      WHERE RN = 1
      ORDER BY actual_time DESC;
      

      ROW_NUMBER() 函数为每一行分配一个数字。 PARTITION BY 是可选的,但用于为该组中的每个值重新开始编号,即:如果您 PARTITION BY origin_city 则对于每个唯一的 origin_city 值,编号将从 1 开始。当然使用 ORDER BY定义计数应该如何进行,并且在 ROW_NUMBER() 函数中是必需的。

      当存在GROUP BY 子句时,许多数据库不允许您在SELECT 列表中拥有不在GROUP BY 子句中的非聚合字段,MySQL 和SQLite 允许这样做,但它可以在某些情况下返回不需要的结果。

      【讨论】:

      • 此处显示了您的原始查询返回不需要的结果的示例:sqlfiddle.com/#!7/fe872/1/0 请注意它如何返回col3 的最低值,即使它是按该字段降序排序的,它也不可靠。
      猜你喜欢
      • 2012-08-13
      • 2019-11-11
      • 2022-01-06
      • 1970-01-01
      • 2021-11-17
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 2020-01-01
      相关资源
      最近更新 更多