2010-08-03 10 views
8

Ho uno studente da tavolo (id, nome, dipartimento, età, punteggio). Voglio trovare lo studente più giovane che ha il punteggio più alto (tra i più giovani) di ciascun dipartimento. In SQL Server, posso usare il seguente SQL.Ottieni la riga superiore dopo l'ordine in Oracle Subquery

select * from student s1 
where s1.id in 
(select s2.id from student s2 
where s2.department = s1.department order by age asc, score desc top 1). 

Tuttavia, in Oracle, non è possibile utilizzare la clausola ORDER BY in subquery e non v'è alcun limite/superiore come parola chiave. Devo unirmi al tavolo dello studente con se stesso due volte per interrogare il risultato. In Oracle, io uso il seguente SQL.

select s1.* from student s1, 
(select s2.department, s2.age, max(s2.score) as max_score from student s2, 
(select s3.department, min(s3.age) as min_age from student s3 group by s3.department) tmp1 where 
s2.department = tmp1.department and s2.age = tmp1.min_age group by s2.department, s2.age) tmp2 
where s1.department =tmp2.department and s1.age = tmp2.age and s1.score=tmp2.max_score 

Qualcuno ha qualche idea per semplificare il suddetto SQL per Oracle.

+1

In Oracle, è possibile * * utilizzare la clausola ORDER BY in una subquery. –

+0

C'è una soluzione molto più semplice, senza funzioni analitiche, vedere la risposta accettata alla mia domanda: http://stackoverflow.com/questions/38180445/oracle-left-join-very-big-table-and-limit-the-joined -rows-to-one-with-the-large – Dany

risposta

24

provare questo

select * from 
    (SELECT id, name, department, age, score, 
    ROW_NUMBER() OVER (partition by department order by age desc, score asc) srlno 
    FROM student) 
where srlno = 1; 
+0

Avevo uno scenario simile, pensavo di gestire l'utilizzo del blocco pl/sql, ma la tua soluzione funzionava perfettamente !! – Rakesh

5

Oltre alla risposta di Bharat, è possibile farlo utilizzando ORDER BY nel sub-query in Oracle (come punto da Jeffrey Kemp):

SELECT * 
FROM student s1 
WHERE s1.id IN (SELECT id 
       FROM (SELECT id, ROWNUM AS rn 
         FROM  student s2 
         WHERE s1.department = s2.department 
         ORDER BY age ASC, score DESC) 
       WHERE rn = 1); 

Se si utilizza questo metodo, si potrebbe essere tentati di rimuovere la sottoquery e utilizzare solo rownum = 1. Ciò comporterebbe il risultato errato in quanto l'ordinamento sarebbe applicato dopo i criteri (si otterrebbe 1 riga che è stata ordinata, non una riga dal set ordinato).

+0

La domanda in realtà chiede la riga superiore di "ogni reparto". Non stai utilizzando il dipartimento per raggruppare i risultati. Probabilmente questa risposta è utile per le persone che esaminano domande simili al titolo senza leggere il contenuto della domanda. Ma voglio sottolineare la differenza per le persone che confrontano le soluzioni (perché non otterranno gli stessi risultati). –

+0

@Protron: buona cattura! Ho aggiornato la risposta. – Allan

1
select to_char(job_trigger_time,'mm-dd-yyyy') ,job_status from 
(select * from kdyer.job_instances ji INNER JOIN kdyer.job_param_values pm 
on((ji.job_id = pm.job_id) and (ji.job_spec_id = '10003') and (pm.param_value='21692')) 
order by ji.job_trigger_time desc) 
where rownum<'2' 
10

Oltre alla risposta di Allan, questo funziona bene anche:

select * 
from (SELECT * 
    FROM student 
    order by age asc, 
      score desc) 
where rownum = 1; 
+0

Restituisce solo la riga superiore dei risultati "tutti". Ciò potrebbe corrispondere al titolo della domanda. Ma la domanda in realtà pone la prima riga di "ogni dipartimento". Ecco perché è più semplice delle risposte di Bharat. –

+0

Questo è vero, Protron, in realtà mi mancava questa distinzione e ho risposto a una domanda più semplice, che era in realtà ciò che stavo cercando da solo quando ho cercato su Google e ho trovato questo thread. Quindi suppongo che tutte le risposte siano corrette e utili, a seconda di ciò che il lettore sta effettivamente cercando. Per il mio scopo, la risposta di Allan era la più utile, quindi l'ho perfezionata e ripubblicata. Per il tuo scopo, la risposta di Bharat è la più utile. Ognuno vince! (Anche se ho notato che Allan ha modificato la sua risposta a causa del tuo suggerimento, ma lascerò il mio così com'è, dato che è una risposta perfetta per molte persone). – SurfingSanta