Domanda

Consideriamo l'Oracolo emp tavolo.Mi piacerebbe coinvolgere i dipendenti con lo stipendio più alto department = 20 E job = clerk.Si supponga inoltre che non esista una colonna "empno" e che la chiave primaria coinvolga un numero di colonne.Puoi farlo con:

select * from scott.emp
where deptno = 20 and job = 'CLERK'
and sal =  (select max(sal) from scott.emp
            where deptno = 20 and job = 'CLERK')

Funziona, ma devo duplicare il test deptno = 20 e job = 'CLERK', cosa che vorrei evitare.Esiste un modo più elegante per scriverlo, magari usando a group by?A proposito, se è importante, sto usando Oracle.

È stato utile?

Soluzione

Quello che segue è un po' troppo ingegnerizzato, ma è un buon modello SQL per le query "top x".

SELECT 
 * 
FROM 
 scott.emp
WHERE 
 (deptno,job,sal) IN
 (SELECT 
   deptno,
   job,
   max(sal) 
  FROM 
   scott.emp
  WHERE 
   deptno = 20 
   and job = 'CLERK'
  GROUP BY 
   deptno,
   job
  )

Tieni inoltre presente che funzionerà in Oracle e Postgress (credo) ma non in MS SQL.Per qualcosa di simile in MS SQL vedi domanda Query SQL per ottenere l'ultimo prezzo

Altri suggerimenti

Se fossi sicuro del database di destinazione, opterei per la soluzione di Mark Nold, ma se mai desideri un SQL* indipendente dal dialetto, prova

SELECT * 
FROM scott.emp e
WHERE e.deptno = 20 
AND e.job = 'CLERK'
AND e.sal = (
  SELECT MAX(e2.sal) 
  FROM scott.emp e2
  WHERE e.deptno = e2.deptno 
  AND e.job = e2.job
)

*Credo che dovrebbe funzionare ovunque, ma non ho gli ambienti per testarlo.

In Oracle lo farei con una funzione analitica, quindi interrogheresti la tabella emp solo una volta:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER () AS max_sal
          FROM scott.emp e
         WHERE deptno = 20 
           AND job = 'CLERK')
 WHERE sal = max_sal

È più semplice, più facile da leggere e più efficiente.

Se desideri modificarlo per elencare queste informazioni per tutti i dipartimenti, dovrai utilizzare la clausola "PARTITION BY" in OVER:

SELECT *
  FROM (SELECT e.*, MAX (sal) OVER (PARTITION BY deptno) AS max_sal
          FROM scott.emp e
         WHERE job = 'CLERK')
 WHERE sal = max_sal
ORDER BY deptno

È fantastico!Non sapevo che potessi fare un confronto tra (x, y, z) con il risultato di un'istruzione SELECT.Funziona benissimo con Oracle.

Come nota a margine per gli altri lettori, nella query di cui sopra manca un "=" dopo "(deptno,job,sal)".Forse il formattatore Stack Overflow se lo è mangiato (?).

Ancora una volta, grazie Marco.

In Oracle puoi anche utilizzare l'istruzione EXISTS, che in alcuni casi è più veloce.

Per esempio...Selezionare il nome, numero da Cust in cui CUST in (selezionare Cust_id da Big_table) e inserito> sysdate -1 sarebbe lento.

Ma seleziona Nome, numero da CURS CDove esiste (seleziona cust_id da big_table DOVE cust_id=c.cust_id ) E inserito> sysdate -1 sarebbe molto veloce con una corretta indicizzazione.Puoi anche usarlo con più parametri.

Ci sono molte soluzioni.Potresti anche mantenere il layout della query originale semplicemente aggiungendo alias di tabella e unendoti ai nomi delle colonne, avresti comunque DEPTNO = 20 e JOB = 'CLERK' nella query una sola volta.

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL =  
    (
      select 
        max(salmax.SAL) 
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

Si potrebbe anche notare che la parola chiave "ALL" può essere utilizzata per questo tipo di query che consentirebbero di rimuovere la funzione "MAX".

SELECT 
  * 
FROM 
  scott.emp emptbl
WHERE
  emptbl.DEPTNO = 20 
  AND emptbl.JOB = 'CLERK'
  AND emptbl.SAL >= ALL  
    (
      select 
        salmax.SAL
      from 
        scott.emp salmax
      where 
        salmax.DEPTNO = emptbl.DEPTNO
        AND salmax.JOB = emptbl.JOB
    )

Spero che questo aiuti e abbia senso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top