Domanda

Sono nuovo nel lavorare con le funzioni analitiche.

DEPT EMP   SALARY
---- ----- ------
  10 MARY  100000
  10 JOHN  200000
  10 SCOTT 300000
  20 BOB   100000
  20 BETTY 200000
  30 ALAN  100000
  30 TOM   200000
  30 JEFF  300000

Voglio il dipartimento e il dipendente con lo stipendio minimo.

I risultati dovrebbero essere simili a:

DEPT EMP   SALARY
---- ----- ------
  10 MARY  100000
  20 BOB   100000
  30 ALAN  100000

MODIFICARE:Ecco l'SQL che ho (ma ovviamente non funziona perché vuole anche lo staff nella clausola group by):

SELECT dept, 
  emp,
  MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary)
FROM mytable
GROUP BY dept
È stato utile?

Soluzione

Penso che la funzione Rank() non sia la strada da percorrere, per due motivi.

Innanzitutto è probabilmente meno efficiente di un metodo basato su Min().

La ragione di ciò è che la query deve mantenere un elenco ordinato di tutti gli stipendi per dipartimento mentre analizza i dati e la classifica verrà quindi assegnata in seguito rileggendo questo elenco.Ovviamente in assenza di indici che possano essere sfruttati a questo scopo, non è possibile assegnare un rango finché non è stato letto l'ultimo dato, e la manutenzione dell'elenco è costosa.

Pertanto, le prestazioni della funzione Rank() dipendono dal numero totale di elementi da sottoporre a scansione e, se il numero è sufficiente a far sì che l'ordinamento venga riversato sul disco, le prestazioni crolleranno.

Questo è probabilmente più efficiente:

select dept,
       emp,
       salary
from
       (
       SELECT dept, 
              emp,
              salary,
              Min(salary) Over (Partition By dept) min_salary
       FROM   mytable
       )
where salary = min_salary
/

Questo metodo richiede solo che la query mantenga un singolo valore per dipartimento rispetto al valore minimo riscontrato finora.Se viene raggiunto un nuovo minimo, il valore esistente viene modificato, altrimenti il ​​nuovo valore viene scartato.Il numero totale di elementi che devono essere mantenuti in memoria è correlato al numero di reparti, non al numero di righe scansionate.

Potrebbe essere che Oracle abbia un percorso di codice per riconoscere che il Rank non ha realmente bisogno di essere calcolato in questo caso, ma non ci scommetterei.

Il secondo motivo per cui Rank() non mi piace è che risponde semplicemente alla domanda sbagliata.La domanda non è "Quali record hanno lo stipendio che è il primo in classifica quando gli stipendi per dipartimento sono in ordine crescente", è "Quali record hanno lo stipendio che è il minimo per dipartimento".Questo, almeno per me, fa una grande differenza.

Altri suggerimenti

Credo che eri abbastanza vicino con la query originale. Quanto segue potrebbe correre e fare abbinare il vostro banco di prova:

SELECT dept, 
  MIN(emp) KEEP(DENSE_RANK FIRST ORDER BY salary, ROWID) AS emp,
  MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary, ROWID) AS salary
FROM mytable
GROUP BY dept

A differenza del RANK () soluzioni, questo garantisce uno al massimo una riga per reparto. Ma che allude ad un problema: cosa succede in un reparto dove ci sono due dipendenti sul salario più basso? Le soluzioni RANK () restituirà sia i dipendenti - più di una riga per il reparto. Questa risposta sarà sceglierne uno arbitrariamente e assicurarsi che non c'è un solo per il reparto.

È possibile utilizzare la sintassi RANK(). Ad esempio, questa query vi dirà dove un dipendente si colloca all'interno del loro reparto per quanto riguarda quanto grande il loro stipendio è:

SELECT
  dept,
  emp,
  salary,
  (RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
FROM EMPLOYEES

È quindi possibile interrogare da questo dove salary_rank_within_dept = 1:

SELECT * FROM
  (
    SELECT
      dept,
      emp,
      salary,
      (RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept
    FROM EMPLOYEES
  )
WHERE salary_rank_within_dept = 1
select e2.dept, e2.emp, e2.salary
from employee e2
where e2.salary = (select min(e1.salary) from employee e1)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top