限制 SQL 中的行数无法正常工作

Limiting rows in SQL doesn't work properly

我想在 select 中获取每个季节的前 5 行。我有 4 个季节:SUM, SPR, AUT, WIN。 所以总共应该有 20 行。 我的 select 看起来像这样:

select *
from (
    select year, season, ROUND(avg(temperature),1) as avgTemp
    from temperature join month on temperature.MONTH = month.MONTH
    group by (season, year)
    order by season, avgTemp asc
) where rownum <= 5;

仅适用一季。输出为:

1993    AUT 8,7
2007    AUT 9,9
1996    AUT 10
1998    AUT 10
2008    AUT 10,5

但它应该是这样的:

 1996 SPR        9.6
  1991 SPR       10.3
  2006 SPR       10.3
  2004 SPR       10.6
  1995 SPR       10.6
  1996 SUM       18.9
  1993 SUM       19.1
  2007 SUM       19.5
  1998 SUM       19.5
  2000 SUM       19.6
  1993 AUT        8.7
  2007 AUT        9.9
  1998 AUT       10.0
  1996 AUT       10.0
  2008 AUT       10.5
  1996 WIN         .3
  1991 WIN        1.2
  2003 WIN        1.6
  2006 WIN        1.9
  2005 WIN        2.0

您知道如何改进 select 或者您有任何其他建议吗?提前致谢!

您需要使用 row_number 为每个分组获取 5 行:

select
    year,
    season,
    round(avg(temperature), 1) as avgTemp
from (
    select *,
        row_number() over(partition by season, year order by season, avgTemp) as rn
    from temperature t
    join month m
        on m.MONTH = t.MONTH
) a
where
    a.rn <= 1
WITH cteAverageTempByYearBySeason AS (
    SELECT
       year
       ,season
       ,ROUND(AVG(temperature),1) as AvgTemp
    FROM
       Temperature t
       INNER JOIN Month m
       On t.MONTH = m.MONTH
    GROUP BY
       year
       ,season
)

, cteRowNumber AS (
    SELECT
       *
       ,ROW_NUMBER() OVER (PARTITION BY season ORDER BY AvgTemp ASC) as RowNumber
    FROM
       cteAverageTempByYearBySeason
)

SELECT *
FROM
    cteRowNumber
WHERE
    RowNumber <= 5

这是一个例子。我将 派生表 分解为 通用 Table 表达式 以使逻辑更加明显。您需要创建一个 PARTITIONED ROW_NUMBER() 而不仅仅是使用 oracles special rownumber。后者只会 return 与 TOP/LIMIT 5 相同,而前者将允许您每个季节识别 5 行。

Edit 为您的 order by 添加了一个巧妙的技巧,因此您不必编写 case 表达式。这个利用了你的月份编号,我假设是 MONTH 列。

WITH cteAverageTempByYearBySeason AS (
    SELECT
       year
       ,season
       ,ROUND(AVG(temperature),1) as AvgTemp
       ,MAX(m.MONTH) as SeasonOrderBy
    FROM
       Temperature t
       INNER JOIN Month m
       On t.MONTH = m.MONTH
    GROUP BY
       year
       ,season
)

, cteRowNumber AS (
    SELECT
       *
       ,ROW_NUMBER() OVER (PARTITION BY season ORDER BY AvgTemp ASC) as RowNumber
    FROM
       cteAverageTempByYearBySeason
)

SELECT
    year
    ,season
    ,AVG
FROM
    cteRowNumber
WHERE
    RowNumber <= 5
ORDER BY
    SeasonOrderBy
    ,AvgTemp
    ,Year

您需要分三步完成:

  1. 按季节和年份分组,计算平均气温
  2. 分配行号:每个季节重新开始,按平均气温升序分配
  3. Select只有行号在1到5之间的行

SQL 应该是这样的(未经测试):

select year, season, avg_temp
from (
    select year, season, avg_temp,
        row_number() over(partition by season order by avg_temp) rn
    from (
        select year, season, ROUND(avg(temperature),1) as avg_temp
        from temperature
        join month on temperature.MONTH = month.MONTH
        group by season, year
    )
)
where rn <= 5;

更新

如果您按季节特别订购,请添加:

order by case season
        when 'SPR' then 1
        when 'SUM' then 2
        when 'AUT' then 3
        when 'WIN' then 4
    end, avg_temp;