2010-05-23 17 views
6

Considerate questo tavolo (da http://www.tizag.com/mysqlTutorial/mysqlmax.php):Come ottenere tutti i campi di una riga utilizzando la funzione SQL MAX?

Id  name    type  price 
123451 Park's Great Hits Music 19.99 
123452 Silly Puddy  Toy  3.99 
123453 Playstation  Toy  89.95 
123454 Men's T-Shirt  Clothing 32.50 
123455 Blouse    Clothing 34.97 
123456 Electronica 2002 Music 3.99 
123457 Country Tunes  Music 21.55 
123458 Watermelon   Food  8.73 

Questa query SQL restituisce l'elemento più costoso da ogni tipo: tipo SELECT, MAX (prezzo) FROM prodotti GROUP BY tipo

Clothing $34.97 
Food  $8.73 
Music $21.55 
Toy  $89.95 

I Voglio anche ottenere i campi id e nome che appartengono al prezzo massimo sopra, per ogni riga. Quale query SQL restituirà una tabella come questa?

Id  name   type  price 
123455 Blouse   Clothing 34.97 
123458 Watermelon  Food  8.73 
123457 Country Tunes Music  21.55 
123453 Playstation  Toy  89.95 
+0

è possibile contrassegnare la tua domanda in modo appropriato per i DBMS che si sta utilizzando? –

+0

Sì, ho aggiunto Firebird 2.1 –

+0

Come devono essere gestiti i legami? Vuoi un solo articolo per tipo o più oggetti se c'è un pareggio per il più costoso? –

risposta

6

Questo è il problema greatest-n-per-group che si presenta frequentemente. Il mio solito modo di risolvere è logicamente equivalente alla risposta data da @ Martin Smith, ma non utilizzare una sottoquery:

SELECT T1.Id, T1.name, T1.type, T1.price 
FROM Table T1 
LEFT OUTER JOIN Table T2 
    ON (T1.type = T2.type AND T1.price < T2.price) 
WHERE T2.price IS NULL; 

La mia soluzione e tutti gli altri dati su questa discussione fino ad ora hanno la possibilità di produrre più righe per valore di type, se più di un prodotto condivide lo stesso tipo ed entrambi hanno un prezzo uguale che è il massimo. Ci sono modi per risolvere questo e rompere il legame, ma è necessario dirci quale prodotto "vince" in questo caso.

È necessario qualche altro attributo che sia garantito come univoco su tutte le righe, almeno per le righe con lo stesso type. Ad esempio, se il prodotto con il maggior valore Id dovrebbe vincere, è possibile risolvere il pareggio in questo modo:

SELECT T1.Id, T1.name, T1.type, T1.price 
FROM Table T1 
LEFT OUTER JOIN Table T2 
    ON (T1.type = T2.type AND (T1.price < T2.price 
     OR T1.price = T2.price AND T1.Id < T2.Id)) 
WHERE T2.price IS NULL; 
+0

Grazie Bill, la seconda query era esattamente quello che stavo cercando. È una piccola domanda, ma complicata per me. –

+0

grazie per continuare a rispondere a questa domanda ogni volta che si apre. Ho dimenticato come farlo ogni 3 mesi circa e come la tua soluzione self-join. – TMG

+0

@TMG: Potrebbe piacerti il ​​mio libro di prossima uscita, * Antipatterns SQL * [http://is.gd/b40bn]. Ho un capitolo su 'GROUP BY'. Puoi mettere un segnalibro sulla pagina con questa soluzione di unione esterna! :-) –

6

Modifica Proprio l'aggiornamento miniera per soddisfare il requisito chiarito

SELECT Id, name, type,price 
FROM Table T1 
WHERE NOT EXISTS(
      SELECT * FROM TABLE T2 
      WHERE T1.type=t2.type 
      AND T2.Price >= T1.Price 
      AND T2.Id > T1.Id 
     ) 
+0

+1: funziona per qualsiasi dialetto SQL. :) – Simon

+0

+1 Ah sì, l'ho già fatto in passato, ma in questo modo solo poche volte l'anno, mi rendo conto di dimenticare il trucco più grande per assicurarti di avere il massimo. – mdma

+0

Sfortunatamente non posso andare avanti a meno che tu non modifichi la tua risposta ... aggiungerebbe uno spazio, pls? :) – Simon

3

È possibile farlo con una subselect

SELECT id, name, type, price FROM products p1 
WHERE EXISTS (Select type, max(price) FROM Products p2 
       GROUP BY type 
       WHERE p1.type=p2.type AND p1.price=p2.MAX(price)) 

o un inner join

SELECT id, name, type, price FROM products p1 
INNER JOIN (Select type, max(price) FROM Products p2 GROUP BY type) maxPrice 
     ON maxPrice=price=p1.price AND maxPrice.type=p1.price 
+0

Grazie a mdma, ma se ci sono più di un articolo con lo stesso prezzo massimo e il tipo restituisce entrambi, ma io ne ho solo bisogno uno –

+0

Ok. Vedo che è già stata scelta una buona risposta, quindi non è necessario aggiornarla. – mdma