2016-06-30 16 views
2

Ich habe ein Problem in Bezug auf SQL-Abfrage, kann es in "plain" SQL getan werden, aber wie ich bin sicher, dass ich eine Gruppe verwenden muss Verkettung (MySQL kann nicht verwendet werden), so ist die zweite Option ORACLE-Dialekt, da es eine Oracle-Datenbank geben wird. Lassen Sie uns sagen, wir haben folgende Einheiten:Oracle ListaGG, Top 3 häufigsten Werte, in einer Spalte, nach ID

Tabelle: Tierarzt Besuche

Visit_Id, 
Animal_id, 
Veterinarian_id, 
Sickness_code 

Lasst uns sagen, dass es 100 Besuche (100 visit_id) und jeweils animal_id Besuche um 20-mal.

Ich brauche eine SELECT, durch Animal_id mit 3 Spalten

  • animal_id
  • Sekunden zeigt Gesamtbetrag der Grippe Besuche für dieses bestimmte Tier gruppiert erstellen (lassen Sie uns sagen, Grippe, sickness_code = 5)
  • Die dritte Spalte zeigt die drei häufigsten Krankheitscodes für jedes Tier an (die drei häufigsten Codes für diese Tier-ID)

Wie geht das? Erste und zweite Spalte sind einfach, aber dritte? Ich weiß, dass ich LISTAGG von Oracle, OVER PARTITION BY, COUNT und RANK verwenden muss, ich habe versucht, es zusammen zu binden, aber nicht wie ich erwartet: Wie sollte diese Abfrage aussehen?

+0

Hallo! Willkommen bei StackOverflow! Könnten Sie einen kleinen Satz von Beispieldaten zusammen mit einem Beispiel für die Ausgabe bereitstellen? – dvsoukup

+0

Bitte lesen Sie [** How-to-Ask **] (http://stackoverflow.com/help/how-to-ask) \t \t Und hier ist ein großartiger Ort, um [** START **] (http: // Spaghettidba.com/2015/04/24/how-to-post-a-t-sql-Frage-auf-einem-öffentlichen-Forum /) zu lernen, wie Sie Ihre Fragequalität verbessern und bessere Antworten erhalten. –

+0

[** So erstellen Sie ein minimales, vollständiges und überprüfbares Beispiel **] (http://stackoverflow.com/help/mcve) Beispiel: Statt 100 Besuche verwenden Sie 10. zwei Tiere und jedes erhält 5 Besuche. und zeige das Ergebnis mit TOP 2 Ergebnis. –

Antwort

1

Ich denke, die natürlichste Art und Weise verwendet zwei Aggregationsebene, zusammen mit einem Hauch von Fensterfunktionen hier und da:

select vas.animal, 
     sum(case when sickness_code = 5 then cnt else 0 end) as numflu, 
     listagg(case when seqnum <= 3 then sickness_code end, ',') within group (order by seqnum) as top3sicknesses 
from (select animal, sickness_code, count(*) as cnt, 
      row_number() over (partition by animal order by count(*) desc) as seqnum 
     from visits 
     group by animal, sickness_code 
    ) vas 
group by vas.animal; 

Dies nutzt die Tatsache, dass listagg() ignoriert NULL Werte

+0

Elegante Lösung mit Ignorieren von NULL und Speichern von Unterabfragen (+1). Bitte korrigieren Sie 'order by count (*)' in 'row_number'. ('cnt' ist nicht definiert) –

+0

@MarmiteBomber. . . Vielen Dank. –

0

hier Beispieldaten

create table VET as 
select 
rownum+1 Visit_Id, 
mod(rownum+1,5) Animal_id, 
cast(NULL as number) Veterinarian_id, 
trunc(10*dbms_random.value)+1 Sickness_code 
from dual 
connect by level <=100; 
. Abfrage

im Grunde die Unterabfragen wie folgt vor:

Gesamtzahl und Grippe Zahl berechnen (in allen Aufzeichnungen des Tieres)

berechnen RANK (wenn Sie wirklich nur 3 Datensätze verwenden ROW_NUMBER - siehe Diskussion unten)

Filter Top-3 Ränge

LISTAGGregate Ergebnis

with agg as (
select Animal_id, Sickness_code, count(*) cnt, 
sum(case when SICKNESS_CODE = 5 then 1 else 0 end) over (partition by animal_id) as cnt_flu 
from vet 
group by Animal_id, Sickness_code 
), agg2 as (
select ANIMAL_ID, SICKNESS_CODE, CNT, cnt_flu, 
rank() OVER (PARTITION BY ANIMAL_ID ORDER BY cnt DESC) rnk 
from agg 
), agg3 as (
select ANIMAL_ID, SICKNESS_CODE, CNT, CNT_FLU, RNK 
from agg2 
where rnk <= 3 
) 
select 
ANIMAL_ID, max(CNT_FLU) CNT_FLU, 
LISTAGG(SICKNESS_CODE||'('||CNT||')', ', ') WITHIN GROUP (ORDER BY rnk) as cnt_lts 
from agg3 
group by ANIMAL_ID 
order by 1; 

gibt

ANIMAL_ID CNT_FLU CNT_LTS          
---------- ---------- --------------------------------------------- 
     0   1 6(5), 1(4), 9(3)        
     1   1 1(5), 3(4), 2(3), 8(3)       
     2   0 1(5), 10(3), 4(3), 6(3), 7(3)     
     3   1 5(4), 2(3), 4(3), 7(3)       
     4   1 2(5), 10(4), 1(2), 3(2), 5(2), 7(2), 8(2) 

ich absichtlich zeigen Sickness_code (Anzahl Besuche) demonstarte, dass Top-3 Bindungen haben können, die Sie behandeln sollten. Überprüfen Sie die RANK-Funktion. Die Verwendung von ROW_NUMBER ist in diesem Fall nicht deterministisch.