我面临一个SQL查询的简单问题,我不知道如何处理。
我有一个包含以下结构的表
CITY COUNTRY DATES TEMPERATURE
请注意,对于特定国家/地区,我可以拥有多个城市。并且,对于给定的城市,我有几行在每个可用的日期给我温度。这只是一个时间系列。
我想写一个查询,它为每个城市提供了TEMPERATURE为MIN的DATE和TEMPERATURE为MAX的DATE。查询应返回类似的内容:
CITY COUNTRY DATE_MIN_TEMPERATURE MIN_TEMPERATURE DATE_MAX_TEMPERATURE MAX_TEMPERATURE
关于如何实现这一目标的任何想法?
致以最诚挚的问候,
拒绝
答案 0 :(得分:1)
Oracle为此提供了keep
/ dense_rank first
:
select city,
min(temperature) as min_temperature,
max(date) keep (dense_rank first order by temperature asc) as min_temperature_date,
max(temperature) as max_temperature,
max(date) keep (dense_rank first order by temperature desc) as max_temperature_date
from t
group by city;
请注意,如果存在关联,则只返回一个日期。如果你想处理它,需要更多的逻辑:
select city, min(temperature) as min_temperature,
listagg(case when seqnum_min = 1 then date end, ',') within group (order by date) as mindates,
max(temperature) as max_temperature,
listagg(case when seqnum_max = 1 then date end, ',') within group (order by date) as maxdates,
from (select t.*,
rank() over (partition by city order by temperature) as seqnum_min,
rank() over (partition by city order by temperature desc) as seqnum_max
from t
) t
where seqnum_min = 1 or seqnum_max = 1
group by city;
答案 1 :(得分:0)
在Oracle 11及更高版本中,您可以使用PIVOT。在下面的解决方案中,我使用LISTAGG显示关系时的所有日期。另一种选择是,在关系的情况下,显示达到极端温度的最近日期;如果这是首选,只需将LISTAGG(dt, ....)
(包括WITHIN GROUP
子句)替换为MAX(dt)
。但是,在这种情况下,Gordon提供的第一个解决方案(使用first
函数)无论如何都更有效 - 无需转动。
请注意,我更改了" date"到" dt" - DATE是Oracle中的保留字。我还首先按国家/地区显示行,然后是城市(更符合逻辑的顺序)。我在WITH子句中创建了测试数据,但解决方案是注释行下面的所有内容。
with
inputs ( city, country, dt, temperature ) as (
select 'Palermo', 'Italy' , date '2014-02-13', 3 from dual union all
select 'Palermo', 'Italy' , date '2002-01-23', 3 from dual union all
select 'Palermo', 'Italy' , date '1998-07-22', 42 from dual union all
select 'Palermo', 'Italy' , date '1993-08-24', 30 from dual union all
select 'Maseru' , 'Lesotho', date '1994-01-11', 34 from dual union all
select 'Maseru' , 'Lesotho', date '2004-08-13', 12 from dual
)
-- >> end test data; solution (SQL query) begins with the next line
select country, city,
"'min'_DT" as date_min_temp, "'min'_TEMP" as min_temp,
"'max'_DT" as date_max_temp, "'max'_TEMP" as max_temp
from (
select city, country, dt, temperature,
case when temperature = min(temperature)
over (partition by city, country) then 'min'
when temperature = max(temperature)
over (partition by city, country) then 'max'
end as flag
from inputs
)
pivot ( listagg(to_char(dt, 'dd-MON-yyyy'), ', ')
within group (order by dt) as dt, min(temperature) as temp
for flag in ('min', 'max'))
order by country, city -- ORDER BY is optional
;
COUNTRY CITY DATE_MIN_TEMP MIN_TEMP DATE_MAX_TEMP MAX_TEMP
------- ------- ------------------------ ---------- -------------- ----------
Italy Palermo 23-JAN-2002, 13-FEB-2014 3 22-JUL-1998 42
Lesotho Maseru 13-AUG-2004 12 11-JAN-1994 34
2 rows selected.
答案 2 :(得分:0)
您可以使用keep/dense_rank first
和FIRST_VALUE
代替LAST_VALUE
功能:
select distinct city,
MIN(temperature) OVER (PARTITION BY city) as min_temperature,
FIRST_VALUE(date) OVER (PARTITION BY city ORDER BY temperature) AS min_temperature_date,
MAX(temperature) OVER (PARTITION BY city) as max_temperature,
LAST_VALUE(date) OVER (PARTITION BY city ORDER BY temperature) AS max_temperature_date
FROM t;