限制 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
您需要分三步完成:
- 按季节和年份分组,计算平均气温
- 分配行号:每个季节重新开始,按平均气温升序分配
- 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;
我想在 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
您需要分三步完成:
- 按季节和年份分组,计算平均气温
- 分配行号:每个季节重新开始,按平均气温升序分配
- 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;