Her grubun ilk satırı nasıl seçilir?


57

Böyle bir masam var:

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

Bunu yapmak SELECTiçin, her birinin yalnızca ilk sırasını Valgöstererek sipariş vermesini istiyorum Kind.

Örnek çıktı:

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

Bu sorguyu nasıl oluşturabilirim?


neden 3 | 3 | 4 ve 4 | 3 | 4 - beraberlik nedir ya da umrunda değil mi?
Jack Douglas

@ JackDouglas Aslında ben bir ORDER BY ID DESC, ama bu soru ile ilgili değil. Bu örnekte umrumda değil.
BrunoLM

Yanıtlar:


38

Bu çözüm aynı zamanda kullanır keep, ancak valve kindaynı zamanda sadece bir alt sorgu olmadan her bir grup için hesaplanabilir:

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

dbfiddle burada

KEEP… İLK ve KEEP… SON, Oracle'a özel toplamaların özelliğidir - bundan sonra burada Oracle dokümanlarında veya ORACLE_BASE'de okuyabilirsiniz :

FIRST ve LAST işlevleri, ilk veya son değeri sıralı bir diziden döndürmek için kullanılabilir.


62

Bir kullan ortak tablo ifade (CTE) ve benzeri bir pencere / sıralaması / bölümleme işlevi ROW_NUMBER .

Bu sorgu SİPARİŞ denilen bir bellek içi tablo oluşturmak ve N. 1 ila sayıların dizisidir rn ek bir sütun katacak BÖLME İLE her seferinde 1 de Val değişikliklerin değerini yeniden gerektiğini gösterir ve biz sipariş etmek istiyorum Türün en küçük değerine göre satırlar.

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;

Yukarıdaki yaklaşım, ROW_NUMBER () işlevini uygulayan herhangi bir RDBMS ile çalışmalıdır. Oracle, Mik'in cevabında ifade edildiği gibi , genellikle bu cevabından daha iyi performans sağlayacak olan bazı zarif fonksiyonlara sahiptir .


25

bilinkc'in çözümü iyi çalışıyor ama benimkileri de dışarı atacağımı düşündüm. Aynı maliyete sahip, ancak daha hızlı olabilir (veya daha yavaş, test etmedim). Aradaki fark, Row_Number yerine First_Value kullanmasıdır. Sadece ilk değer ile ilgilendiğimiz için bence daha kolay.

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;

Test verisi.

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

Tercih ederseniz, işte CTE eşdeğeri.

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;

1
+1 ama sadece cevabınızın ve billinkc'lerin idbenzersiz olmadığı sürece mantıksal olarak aynı olmadığını vurgulamaya değeceğini düşündüm .
Jack Douglas

@ Jack Douglas - Doğru, bunu varsaydım.
Leigh Riffel

14

Her gruptan keepbir tane seçmek için kullanabilirsiniz id:

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

dbfiddle burada


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

Bu, MyTable üzerinden iki taramaya ihtiyaç duyulması nedeniyle diğer cevaplardan çok daha az etkili olacaktır.
a_horse_with_no_name 22:13

2
Bu, yalnızca optimizer yazılı sorguyu tam anlamıyla alırsa geçerlidir. Daha gelişmiş optimize ediciler amacı (grup başına satır) görebilir ve tek bir masa erişimine sahip bir plan yapabilir.
Paul White
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.