web-dev-qa-db-ja.com

Oracle SQL-グループ全体の分析関数?

私のテーブル:

ID   NUM   VAL
1    1     Hello
1    2     Goodbye
2    2     Hey
2    4     What's up?
3    5     See you

各IDの最大数を返したい場合、それは本当に素晴らしくてきれいです:

SELECT MAX(NUM) FROM table GROUP BY (ID)

しかし、各IDの各番号の最大値に関連付けられた値を取得したい場合はどうなりますか?

なぜできないのですか:

SELECT MAX(NUM) OVER (ORDER BY NUM) FROM table GROUP BY (ID) 

なぜそれがエラーなのですか?ウィンドウごとに個別にパーティション化するのではなく、この選択をIDでグループ化したいと思います...

編集:エラーは「GROUPBY式ではありません」です。

11
Jeremy

おそらくMAX() KEEP(DENSE_RANK LAST...)関数を使用できます。

with sample_data as (
  select 1 id, 1 num, 'Hello' val from dual union all
  select 1 id, 2 num, 'Goodbye' val from dual union all
  select 2 id, 2 num, 'Hey' val from dual union all
  select 2 id, 4 num, 'What''s up?' val from dual union all
  select 3 id, 5 num, 'See you' val from dual)
select id, max(num), max(val) keep (dense_rank last order by num)
from sample_data
group by id;
16
Wolf

ウィンドウ関数を使用する場合、GROUPBYを使用する必要はありません。これで十分です。

select id, 
     max(num) over(partition by id) 
from x 

実際には、ウィンドウ関数を使用せずに結果を得ることができます。

select * 
from x
where (id,num) in
  (
     select id, max(num) 
     from x 
     group by id
  )

出力:

ID  NUM VAL
1   2   Goodbye
2   4   What's up
3   5   SEE YOU

http://www.sqlfiddle.com/#!4/a9a07/7


ウィンドウ関数を使用する場合は、次のようにします。

select id, val, 
     case when num =  max(num) over(partition by id) then
        1
     else
        0
     end as to_select
from x 
where to_select = 1

またはこれ:

select id, val 
from x 
where num =  max(num) over(partition by id) 

しかし、それらを行うことは許可されていないため、これを行う必要があります。

with list as
(
  select id, val, 
     case when num =  max(num) over(partition by id) then
        1
     else
        0
     end as to_select
  from x
)
select * 
from list 
where to_select = 1

http://www.sqlfiddle.com/#!4/a9a07/19

4
Michael Buen

MAX(num) GROUP BY idからの値を含むを取得しようとしている場合、これは一般的なパターンになる傾向があります。

WITH
  sequenced_data
AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY num DESC) AS sequence_id,
    *
  FROM
    yourTable
)
SELECT
  *
FROM
  sequenced_data
WHERE
  sequence_id = 1


[〜#〜]編集[〜#〜]

TeraDataがこれを許可するかどうかはわかりませんが、ロジックは理にかなっているようです...

SELECT
  *
FROM
  yourTable
WHERE
  num = MAX(num) OVER (PARTITION BY id)

または多分...

SELECT
  *
FROM
(
  SELECT
    *,
    MAX(num) OVER (PARTITION BY id) AS max_num_by_id
  FROM
    yourTable
)
  AS sub_query
WHERE
  num = max_num_by_id 

これは私の以前の答えとは少し異なります。複数のレコードが同じMAX(num)で関連付けられている場合、これはそれらすべてを返し、他の回答は1つだけを返します。


[〜#〜]編集[〜#〜]

提案されたSQLでは、エラーはOVER()句にGROUPBYにないフィールドが含まれているという事実に関連しています。これをやろうとしているようなものです...

SELECT id, num FROM yourTable GROUP BY id

numは無効です。これは、返される行ごとにそのフィールドに複数の値が存在する可能性があるためです(返される行はGROUP BY idによって定義されます。

同様に、OVER()句の中にnumを入れることはできません。

SELECT

  id,

  MAX(num),                <-- Valid as it is an aggregate

  MAX(num)                 <-- still valid
  OVER(PARTITION BY id),   <-- Also valid, as id is in the GROUP BY

  MAX(num)                 <-- still valid
  OVER(PARTITION BY num)   <-- Not valid, as num is not in the GROUP BY

FROM
  yourTable
GROUP BY
  id


OVER()句で何かを指定できない場合は、この質問を参照してください。また、(私は思う)ができる場合を示す回答: over -質問ごとのパーティション

3
MatBailie