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

时间:2016-12-04 21:58:20

标签: sql oracle-sqldeveloper

我希望在我的选择中获得每个赛季的前5行。我有4个赛季:SUM, SPR, AUT, WIN。 所以总共应该有20行。 我的选择看起来像这样:

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

您知道如何改善选择或者您有其他建议吗?提前谢谢!

3 个答案:

答案 0 :(得分:2)

您需要分三步完成:

  1. 按季节和年份分组,计算平均温度
  2. 指定一个行号:每个季节重新开始,并根据平均温度按升序分配
  3. 仅选择行号介于1和5之间的行
  4. 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;
    

答案 1 :(得分: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

这是一个例子。我将派生表分解为公用表表达式,以使逻辑更加明显。您需要创建一个PARTITIONED ROW_NUMBER(),而不仅仅是使用特殊的rownumber。后者只返回与TOP/LIMIT 5相同的位置,因为前者允许您每季识别5行。

编辑为您的订单添加了一个巧妙的技巧,因此您不必编写案例表达式。这个使用你的月号,我假设它是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

答案 2 :(得分:0)

您需要使用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