2016-10-30 5 views
2

私はどのように対処するかわからないSQLクエリには簡単な問題があります。すべてのフィールドでSQL min/maxを

私は与えられた国のために、私はいくつかの都市を持つことができることは、以下の構造

CITY COUNTRY DATES TEMPERATURE 

注意を持つテーブルがあります。そして、与えられた都市では、利用可能な日付ごとにTEMPERATUREを与える行がいくつかあります。これはちょうど時系列です。

私はすべての都市に対して、TEMPERATUREがMINであるDATEとTEMPERATUREがMAXであるDATEを与えるクエリを作成したいと思います。クエリは次のようなものを返す必要があります:

CITY COUNTRY DATE_MIN_TEMPERATURE MIN_TEMPERATURE DATE_MAX_TEMPERATURE MAX_TEMPERATURE 

これを達成する方法についてのアイデアはありますか?

敬具、

+0

指定した都市の最低温度が達成された二つの異なる日がある場合に示す何をしたいですか? – mathguy

+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; 
+0

'first'と' last'関数は集計関数として 'listagg'と一緒に使えません! (なぜ彼らがなぜそうしないのかは明らかではありませんが、そうではありません)。両方のアイデアを一つにまとめることは可能でしょうか。 – mathguy

+0

err ... 2番目の解決策にはいくつかの欠落したキーワード、タイプミス、「日付」が列名として機能しません。これらのすべてを修正した後、解決策が間違った答えを出します。 (おそらく、2番目のrow_number()コールが温度** desc **によって注文する必要があるからです)そして、 'row_number()'であってはなりません。あまりにも多くのエラー。 – mathguy

+0

@mathguy。 。 。 'date'はOPによって提供される列です。おそらく実際の列の名前ではないので、それをエスケープする理由はありません。他のタイプミスは修正されていると思います。 'rank()'に対するコメントは非常に重要ですが、実際にはOPの質問に実際に答える最初のクエリです。 –

0

Oracle 11以上では、PIVOTを使用できます。下のソリューションでは、私はLISTAGGを使用して、ネクタイの場合のすべての日付を表示します。別の選択肢は、ネクタイの場合、極端な温度に達したときの最新の日付を表示することです。これが望ましい場合は、LISTAGG(dt, ....)WITHIN GROUP句を含む)をMAX(dt)に置き換えてください。しかし、その場合、Gordonが提供する最初のソリューション(first関数を使用)は、とにかく効率的です。ピボットを必要としません。

「date」を「dt」に変更しました.DATEはOracleでは予約語です。私はまた、まず国、次に都市(より論理的な順序)の行を示します。 WITH句でテストデータを作成しましたが、解決策はコメント行の下にあります。代わりにkeep/dense_rank first機能の

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. 
0

あなたもFIRST_VALUELAST_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; 
関連する問題