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?
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
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ěď.
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;
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;
vyberte * z (vyberte t1. *, ROW_NUMBER () OVER (PARTITION by Val ORDER BY Val desc) jako seqnum z tablename t1) kde seqnum = 1;