web-dev-qa-db-ja.com

各グループの最初の行を選択するにはどうすればよいですか?

私はこのようなテーブルを持っています:

 ID |  Val   |  Kind
----------------------
 1  |  1337  |   2
 2  |  1337  |   1
 3  |   3    |   4
 4  |   3    |   4

SELECTの最初の行だけを返し、Valの順に並べるKindを作成します。

出力例:

 ID |  Val   |  Kind
----------------------
 2  |  1337  |   1
 3  |   3    |   4

このクエリを作成するにはどうすればよいですか?

59
BrunoLM

このソリューションもkeepを使用しますが、valkindは、サブクエリを使用せずに、各グループに対して単純に計算することもできます。

select min(id) keep(dense_rank first order by kind) id
     , val
     , min(kind) kind
  from mytable
 group by val;
 ID | VAL |種類
-:| ---:| ---:
 3 | 3 | 4 
 2 | 1337 | 1 

dbfiddle ここ

KEEP…FIRSTおよびKEEP…LASTは、アグリゲートのOracle固有の機能です。Oracleドキュメントで here 、または Oracle_BASE について読むことができます。

FIRST関数とLAST関数を使用して、順序付けられたシーケンスの最初または最後の値を返すことができます

39
mik

共通テーブル式 (CTE)と ROW_NUMBER のようなウィンドウ処理/ランキング/分割関数を使用します。

このクエリは、ORDEREDと呼ばれるメモリ内テーブルを作成し、1からNまでの数字のシーケンスであるrnの追加の列を追加します。 PARTITION BY は、値がValが変更され、Kindの最小値で行を並べ替えます。

WITH ORDERED AS
(
SELECT
    ID
,   Val
,   kind
,   ROW_NUMBER() OVER (PARTITION BY Val ORDER BY Kind ASC) AS rn
FROM
    mytable
)
SELECT
    ID
,   Val
,   Kind
FROM
    ORDERED
WHERE
    rn = 1;

上記のアプローチは、ROW_NUMBER()関数を実装したRDBMSで機能します。 Oracleには mikの回答 で表されるようなエレガントな機能がいくつかあります。これにより、一般にこの回答よりも優れたパフォーマンスが得られます。

65
billinkc

bilinkcの解決策は問題なく機能しますが、私も同じように取り除きます。それは同じコストですが、より速いかもしれません(または遅いです、私はそれをテストしていません)。違いは、Row_NumberではなくFirst_Valueを使用することです。私たちは最初の値にのみ関心があるので、私の心の中でそれはもっと簡単です。

SELECT ID, Val, Kind FROM
(
   SELECT First_Value(ID) OVER (PARTITION BY Val ORDER BY Kind) First, ID, Val, Kind 
   FROM mytable
)
WHERE ID = First;

テストデータ。

--drop table mytable;
create table mytable (ID Number(5) Primary Key, Val Number(5), Kind Number(5));

insert into mytable values (1,1337,2);
insert into mytable values (2,1337,1);
insert into mytable values (3,3,4);
insert into mytable values (4,3,4);

必要に応じて、これは同等のCTEです。

WITH FirstIDentified AS (
   SELECT First_Value(ID) OVER (PARTITION BY Val ORDER BY Kind) First, ID, Val, Kind 
   FROM mytable
   )
SELECT ID, Val, Kind FROM FirstIdentified
WHERE ID = First;
26
Leigh Riffel

keepを使用して、各グループからidを選択できます。

select *
from mytable
where id in ( select min(id) keep (dense_rank first order by kind, id)
              from mytable
              group by val );
 ID | VAL |種類
-:| ---:| ---:
 2 | 1337 | 1 
 3 | 3 | 4 

dbfiddle ここ

SELECT MIN(MyTable01.Id) as Id,
       MyTable01.Val     as Val,
       MyTable01.Kind    as Kind 
  FROM MyTable MyTable01,                         
       (SELECT Val,MIN(Kind) as Kind
          FROM MyTable                   
      GROUP BY Val) MyTableGroup
WHERE MyTable01.Val  = MyTableGroup.Val
  AND MyTable01.Kind = MyTableGroup.Kind
GROUP BY MyTable01.Val,MyTable01.Kind
ORDER BY Id;
3
fredy

select * from(select t1。*、ROW_NUMBER()OVER(PARTITION BY Val ORDER BY Val desc)as seqnum from tablename t1)where seqnum = 1;

0
Durgesh Yadav