Ich habe einen Tisch wie diesen:
ID | Val | Kind
----------------------
1 | 1337 | 2
2 | 1337 | 1
3 | 3 | 4
4 | 3 | 4
Ich möchte ein SELECT
erstellen, das nur die erste Zeile für jedes Val
zurückgibt, sortiert nach Kind
.
Beispielausgabe:
ID | Val | Kind
----------------------
2 | 1337 | 1
3 | 3 | 4
Wie kann ich diese Abfrage erstellen?
Diese Lösung verwendet auch keep
, aber val
und kind
können auch einfach für jede Gruppe ohne Unterabfrage berechnet werden:
select min(id) keep(dense_rank first order by kind) id , val , min(kind) kind from mytable group by val;
ID | VAL | ART -: | ---: | ---: 3 | 3 | 4 2 | 1337 | 1
dbfiddle hier
KEEP… FIRST und KEEP… LAST sind eine Oracle-spezifische Funktion von Aggregaten - Sie können dann hier in den Oracle-Dokumenten oder auf Oracle_BASE :
Mit den Funktionen FIRST und LAST kann der erste oder letzte Wert aus einer geordneten Sequenz zurückgegeben werden
Verwenden Sie ein allgemeiner Tabellenausdruck (CTE) und eine Fenster-/Ranking-/Partitionierungsfunktion wie ROW_NUMBER .
Diese Abfrage erstellt eine speicherinterne Tabelle mit dem Namen ORDERED und fügt eine zusätzliche Spalte von rn hinzu, die eine Folge von Zahlen von 1 bis N ist. Das PARTITION BY gibt an, dass jedes Mal, wenn der Wert von 1 neu gestartet wird Val ändert sich und wir möchten Zeilen nach dem kleinsten Wert von Kind ordnen.
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;
Der obige Ansatz sollte mit jedem RDBMS funktionieren, das die Funktion ROW_NUMBER () implementiert hat. Oracle verfügt über einige elegante Funktionen, die in Antwort von mik ausgedrückt werden und im Allgemeinen eine bessere Leistung als diese Antwort liefern.
die Lösung von bilinkc funktioniert gut, aber ich dachte, ich würde meine auch rauswerfen. Es hat die gleichen Kosten, ist aber möglicherweise schneller (oder langsamer, ich habe es nicht getestet). Der Unterschied besteht darin, dass der First_Value anstelle von Row_Number verwendet wird. Da wir nur am ersten Wert interessiert sind, ist es meiner Meinung nach einfacher.
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;
Testdaten.
--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);
Wenn Sie es vorziehen, finden Sie hier das CTE-Äquivalent.
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;
Mit keep
können Sie aus jeder Gruppe ein id
auswählen:
select * from mytable where id in ( select min(id) keep (dense_rank first order by kind, id) from mytable group by val );
ID | VAL | ART -: | ---: | ---: 2 | 1337 | 1 3 | 3 | 4
dbfiddle hier
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;
wählen Sie * aus (wählen Sie t1. *, ROW_NUMBER () OVER (PARTITION BY Val ORDER BY Val desc) als Seqnum aus Tabellenname t1), wobei Seqnum = 1;