2010-08-28 12 views
7

Ich habe eine Tabelle namens order, die die Spalten id, user_id, price und item_id enthält. Die Artikelpreise sind nicht festgelegt und ich möchte die teuerste Bestellung jedes Artikels auswählen. Ich möchte user_id, item_id und price in derselben Abfrage auswählen. Ich habe versucht, die folgende Abfrage, aber es gibt nicht die richtige Ergebnismenge zurück.Mehrere Maximalwerte auswählen

SELECT user_id, item_id, MAX(price) 
FROM order 
GROUP BY item_id 

Einige der von dieser Abfrage zurückgegebenen Zeilen haben die falsche user_id. Alle Zeilen in der Ergebnismenge zeigen jedoch den korrekten höchsten Preis für jeden Artikel an.

Antwort

9

Möglicherweise möchten Sie eine abgeleitete Tabelle verwenden, wie folgt:

SELECT o1.item_id, o1.max_price, o2.user_id user_of_max_price 
FROM  (
      SELECT item_id, MAX(price) max_price 
      FROM `order` 
      GROUP BY item_id 
     ) o1 
JOIN  `order` o2 ON (o2.price = o1.max_price AND o2.item_id = o1.item_id) 
GROUP BY o1.item_id; 

Testfall:

CREATE TABLE `order` (user_id int, item_id int, price decimal(5,2)); 

INSERT INTO `order` VALUES (1, 1, 10); 
INSERT INTO `order` VALUES (1, 2, 15); 
INSERT INTO `order` VALUES (1, 3, 8); 
INSERT INTO `order` VALUES (2, 1, 20); 
INSERT INTO `order` VALUES (2, 2, 6); 
INSERT INTO `order` VALUES (2, 3, 15); 
INSERT INTO `order` VALUES (3, 1, 18); 
INSERT INTO `order` VALUES (3, 2, 13); 
INSERT INTO `order` VALUES (3, 3, 10); 

Ergebnis:

+---------+-----------+-------------------+ 
| item_id | max_price | user_of_max_price | 
+---------+-----------+-------------------+ 
|  1 |  20.00 |     2 | 
|  2 |  15.00 |     1 | 
|  3 |  15.00 |     2 | 
+---------+-----------+-------------------+ 
3 rows in set (0.00 sec) 
+0

Es hat perfekt funktioniert. Danke, Daniel! – Ohas

1

Ihre Abfrage gruppiert die Zeilen nach item_id. Wenn Sie mehrere Artikel mit item_id 1 haben, mit einem anderen user_id, wird nur die erste user_id, nicht die user_id mit dem höchsten Preis auswählen.

+0

Ja, das stimmt. Wie kann ich erreichen, was ich hier versuche? Ich versuche herauszufinden, wer den Artikel zum besten Preis gekauft hat und wie hoch dieser Preis war. – Ohas

0

Sie müssen entweder nach item_id UND user_id gruppieren (zeigt den maximalen Preis pro Artikel pro Benutzer), oder wenn Sie nur das Element in der Gruppe möchten, müssen Sie die Spalte user_id überdenken. z.B. Zeigen Sie den Höchstpreis für einen Artikel und zeigen Sie den LETZTEN Benutzer an, der eine Preisänderung vorgenommen hat, ODER zeigen Sie den Höchstpreis für einen Artikel an und zeigen Sie dem Benutzer, der den Höchstpreis für den Artikel usw. gemacht hat. Für einige Muster sehen Sie sich this post an dafür tun.

+0

Kann ich den Artikel, seinen Höchstpreis und den Benutzer, der diesen Preis in einer Abfrage erstellt hat, nicht abrufen? – Ohas

2

Sie müssen zuerst den Höchstpreis für jede Artikel-ID erhalten und dann wieder zu order gehen, um Datensätze zu erhalten, wo der Artikel zum Höchstpreis bestellt wurde. So etwas wie die folgende Abfrage sollte funktionieren. Allerdings werden alle Datensätze mit den maximalen Artikelpreisen zurückgegeben.

SELECT user_id, item_id, price 
FROM order o 
JOIN (
     SELECT item_id, max(price) max_price 
     FROM order 
     GROUP BY item_id 
    ) o2 
    ON o.item_id = o2.item_id AND o.price = o2.max_price; 
2

Dies ist eine per- Gruppen-Maximum-Frage. Es gibt various approaches zu diesem häufigen Problem. Auf MySQL ist es in der Regel schneller und einfacher ein verwenden Null-Self-Join als alles beteiligt Subqueries:

SELECT o0.user_id, o0.item_id, o0.price 
FROM order AS o0 
LEFT JOIN order AS o1 ON o1.item_id=o0.item_id AND o1.price>o0.price 
WHERE o1.user_id IS NULL 

dh. "Wählen Sie jede Zeile aus, in der für denselben Artikel keine andere Zeile mit einem höheren Preis existiert".

(Wenn zwei Reihen den gleichen maximalen Preis haben erhalten Sie beide zurück. Was genau im Fall eines Unentschiedens zu tun, ist ein generelles Problem für pro-Gruppe-Maximum-Lösungen.)

+1

Zeigt der Benchmark in [den Link, den Sie zur Verfügung gestellt haben] (http://kristiannielsen.livejournal.com/6745.html) nicht, dass die abgeleitete Tabelle (unkorrelierte Unterabfrage) viel schneller ist als der Null-Self-Join? ... Ich dachte auch, dass Null-Self-Join in MySQL etwas schneller ist, und ich bin in der Tat sehr überrascht von diesen Benchmarks. Ich habe das Gefühl, dass ich selbst einige Tests machen werde ... ... +1 sowieso –

+1

Ja, die Ergebnisse werden natürlich variieren, abhängig von der Größe der beteiligten Tabellen und Indizes. Normalerweise habe ich den Null-Self-Join in der Vergangenheit am schnellsten über meine bestimmte Datenmenge gefunden, wobei ich MySQL verwendet habe (dessen Unterstützung für Unterabfragen bekanntlich relativ jung ist, also vielleicht nicht so optimiert wie es sein könnte). Es wäre interessant, mehr mit einer aktuellen Version von MySQL zu untersuchen. – bobince

1
SELECT user_id, item_id, MAX(price) 
FROM order 
GROUP BY item_id 

Des Das von Ihnen verwendete SQL ist von GROUP widersprüchlich. Sobald Sie GROUP verwenden, wählt MYSQL immer die erste user_id, aber den höchsten Preis, das ist der Grund, warum der Benutzer falsch ist, aber der Preis stimmt.

Sie können versuchen, ORDER BY price DESC hinzufügen, um zu sehen, was passiert, aber ich habe nicht in meiner Umgebung versucht.

3

Vielleicht ist das ein wenig länger, aber Sie gewinnen in Lesbarkeit

SELECT 
     * 
FROM 
    `order` 
JOIN 
    (
     SELECT 
      item_id, 
      MAX(price) price 
     FROM 
      `order` 
     GROUP BY 
      item_id 
    ) 
    USING(item_id, price); 
0

, wenn Sie oben wollen 2 aus, um dieses versuchen ...

wenn Sie Top-3 wollen, dann letzte Bedingung ändern, nur wo item_rank in (1,2) ;

select * from 
    (select item_id , price 
    , @curRow % @curNval as item_rank 
    , @curRow := @curRow + 1 AS row_number 
    from `order` , (SELECT @curRow := 1 , @curNval := 3) r 
    order by item_id , price desc ) tab where item_rank in (1,2) ; 
+0

kann als item_rank> 2 oder item_rank> n verwendet werden – Kapil

Verwandte Themen