it-swarm-eu.dev

Jak vybrat první řádek každé skupiny?

Mám takovýto stůl:

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

Chci vytvořit SELECT, který vrátí pouze první řádek pro každý Val, seřazený podle Kind.

Ukázkový výstup:

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

Jak mohu vytvořit tento dotaz?

59
BrunoLM

Toto řešení také používá keep, ale val a kind lze také snadno spočítat pro každou skupinu bez poddotazu:

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

dbfiddle zde

KEEP… FIRST and KEEP… LAST jsou funkce agregátů specifické pro Oracle - o nich si pak můžete přečíst v zde v dokumentech Oracle nebo na Oracle_BASE :

Funkce FIRST a LAST lze použít k vrácení první nebo poslední hodnoty z uspořádané sekvence

39
mik

Použijte běžný výraz tabulky (CTE) a funkci okna/žebříčku/rozdělení, jako ROW_NUMBER .

Tento dotaz vytvoří tabulku v paměti s názvem ORDERED a přidá další sloupec rn, což je posloupnost čísel od 1 do N. PARTITION BY znamená, že by se měl restartovat vždy po 1 Val se mění a chceme řadit řádky podle nejmenší hodnoty druhu.

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;

Výše uvedený přístup by měl fungovat s jakýmkoli RDBMS, který implementoval funkci ROW_NUMBER (). Oracle má nějakou elegantní funkci vyjádřenou v mikova odpověď , která obecně poskytne lepší výkon než tato odpověď.

65
billinkc

bilinkc řešení funguje dobře, ale myslel jsem si, že hodím i moje. Má stejné náklady, ale může být rychlejší (nebo pomalejší, netestoval jsem to). Rozdíl je v tom, že používá hodnotu First_Value místo Row_Number. Protože nás zajímá pouze první hodnota, je to podle mě jednodušší.

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;

Testovací data.

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

Pokud dáváte přednost, zde je ekvivalent 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

Pomocí keep můžete vybrat id z každé skupiny:

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

dbfiddle zde

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

vyberte * z (vyberte t1. *, ROW_NUMBER () OVER (PARTITION by Val ORDER BY Val desc) jako seqnum z tablename t1) kde seqnum = 1;

0
Durgesh Yadav