it-swarm.asia

Bagaimana cara memilih baris pertama dari setiap grup?

Saya punya tabel seperti ini:

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

Saya ingin membuat SELECT yang akan mengembalikan hanya baris pertama untuk setiap Val, memesan dengan Kind.

Output sampel:

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

Bagaimana saya bisa membangun kueri ini?

59
BrunoLM

Solusi ini juga menggunakan keep, tetapi val dan kind juga dapat dengan mudah dihitung untuk setiap grup tanpa subquery:

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

dbfiddle di sini

TETAP… PERTAMA dan TETAP… TERAKHIR adalah fitur agregat spesifik Oracle - Anda dapat membaca tentang itu di sini di Oracle docs, atau di Oracle_BASE :

Fungsi PERTAMA dan TERAKHIR dapat digunakan untuk mengembalikan nilai pertama atau terakhir dari urutan yang dipesan

39
mik

Gunakan ekspresi tabel umum (CTE) dan fungsi windowing/peringkat/partisi seperti ROW_NUMBER .

Kueri ini akan membuat tabel dalam-memori yang disebut ORDERED dan menambahkan kolom tambahan rn yang merupakan urutan angka dari 1 hingga N. The PARTITION BY menunjukkan bahwa ia harus memulai ulang pada 1 setiap kali nilai dari Val berubah dan kami ingin memesan baris dengan nilai terkecil dari Jenis.

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;

Pendekatan di atas harus bekerja dengan RDBMS yang telah menerapkan fungsi ROW_NUMBER (). Oracle memiliki beberapa fungsi elegan seperti dinyatakan dalam jawaban mik yang umumnya akan menghasilkan kinerja yang lebih baik daripada jawaban ini.

65
billinkc

solusi bilinkc bekerja dengan baik, tapi saya pikir saya akan membuang milik saya juga. Ini memiliki biaya yang sama, tetapi mungkin lebih cepat (atau lebih lambat, saya belum mengujinya). Perbedaannya adalah bahwa ia menggunakan Nilai First_ alih-alih Row_Number. Karena kita hanya tertarik pada nilai pertama, dalam pikiranku itu lebih mudah.

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;

Data Uji.

--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);

Jika Anda suka, di sini adalah setara 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

Anda dapat menggunakan keep untuk memilih id dari setiap grup:

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

dbfiddle di sini

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

pilih * dari (pilih t1. *, ROW_NUMBER () OVER (PARTITION BY Val ORDER BY Val desc) sebagai seqnum dari tablename t1) di mana seqnum = 1;

0
Durgesh Yadav