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.