2012-07-27 8 views
9

Mein Sortiertisch titles sehen wie folgt ausMySQL nach Datum mit GROUP BY

id |group|date    |title 
---+-----+--------------------+-------- 
1 |1 |2012-07-26 18:59:30 | Title 1 
2 |1 |2012-07-26 19:01:20 | Title 2 
3 |2 |2012-07-26 19:18:15 | Title 3 
4 |2 |2012-07-26 20:09:28 | Title 4 
5 |2 |2012-07-26 23:59:52 | Title 5 

I neuestes Ergebnis aus jeder Gruppe nach Datum geordnet müssen in absteigender Reihenfolge. So etwas wie dieses

id |group|date    |title 
---+-----+--------------------+-------- 
5 |2 |2012-07-26 23:59:52 | Title 5 
2 |1 |2012-07-26 19:01:20 | Title 2 

versuchte ich

SELECT * 
FROM `titles` 
GROUP BY `group` 
ORDER BY MAX(`date`) DESC 

aber ich bin geting erste Ergebnisse aus den Gruppen. Gefällt mir

id |group|date    |title 
---+-----+--------------------+-------- 
3 |2 |2012-07-26 18:59:30 | Title 3 
1 |1 |2012-07-26 19:18:15 | Title 1 

Was mache ich falsch? Wird diese Abfrage komplizierter, wenn ich LEFT JOIN verwende?

+0

Wenn Sie nur die beiden Spalten benötigen (z. B. ID und den letzten Zeitstempel), könnte dies funktionieren: http://stackoverflow.com/a/4448536/722036. Es ist ** schneller ** als die Verwendung von Unterabfragen in einer riesigen Tabelle mit Millionen von Zeilen. –

Antwort

8

This page war sehr hilfreich für mich; Es brachte mir bei, wie man Self-Joins benutzt, um die Max/Min/Something-n-Zeilen pro Gruppe zu erhalten.

In Ihrer Situation, kann es auf die Wirkung angewendet werden, sollten Sie in etwa so:

SELECT * FROM 
(SELECT group, MAX(date) AS date FROM titles GROUP BY group) 
AS x JOIN titles USING (group, date); 
0

Nun, wenn Daten in einer Gruppe eindeutig sind dies funktionieren würde (wenn nicht, werden Sie mehrere Zeilen sehen, dass passe das maximale Datum in einer Gruppe an). (Auch schlechte Benennung der Spalten, ‚Gruppe‘, ‚Datum‘ könnten Sie Syntaxfehler und so speziell ‚Gruppe‘)

select t1.* from titles t1, (select group, max(date) date from titles group by group) t2 
where t2.date = t1.date 
and t1.group = t2.group 
order by date desc 
0

Ein weiterer Ansatz ist die Verwendung von MySQL Benutzervariablen, um einen „Gruppenwechsel zu identifizieren "in den group Werten.

Wenn Sie mit einer extra Spalte zurückgegeben leben können, so etwas wie dies funktioniert:

SELECT IF(s.group = @prev_group,0,1) AS latest_in_group 
    , s.id 
    , @prev_group := s.group AS `group` 
    , s.date 
    , s.title 
    FROM (SELECT t.id,t.group,t.date,t.title 
      FROM titles t 
     ORDER BY t.group DESC, t.date DESC, t.id DESC 
     ) s 
    JOIN (SELECT @prev_group := NULL) p 
HAVING latest_in_group = 1 
ORDER BY s.group DESC 

Was dies tut, alle Zeilen von group wird die Bestellung und durch date in absteigender Reihenfolge. (Wir geben DESC für alle Spalten in ORDER BY an, falls es einen Index für (group,date,id) gibt, den MySQL "reverse scan" ausführen kann. Die Einfügung der Spalte id führt uns zu einem deterministischen (wiederholbaren) Verhalten, in dem Fall Es gibt mehr als eine Zeile mit dem letzten date Wert.) Das ist die Inline-Ansicht aliased als s.

Der "Trick", den wir verwenden, besteht darin, den group Wert mit dem group Wert aus der vorherigen Zeile zu vergleichen. Wann immer wir einen anderen Wert haben, wissen wir, dass wir eine "neue" Gruppe beginnen und dass diese Zeile die "letzte" Zeile ist (wir haben die IF-Funktion, die eine 1 zurückgibt). Ansonsten (wenn die Gruppenwerte übereinstimmen), ist es nicht die letzte Zeile (und die IF-Funktion gibt eine 0 zurück).

Dann filtern wir alle Zeilen, die nicht latest_in_group als 1 gesetzt haben.

Es ist möglich, dass zusätzliche Spalt zu entfernen, indem die Abfrage (als Inline-Ansicht) in einer anderen Abfrage Verpackung:

SELECT r.id 
    , r.group 
    , r.date 
    , r.title 
    FROM (SELECT IF(s.group = @prev_group,0,1) AS latest_in_group 
       , s.id 
       , @prev_group := s.group AS `group` 
       , s.date 
       , s.title 
      FROM (SELECT t.id,t.group,t.date,t.title 
        FROM titles t 
        ORDER BY t.group DESC, t.date DESC, t.id DESC 
       ) s 
      JOIN (SELECT @prev_group := NULL) p 
     HAVING latest_in_group = 1 
     ) r 
ORDER BY r.group DESC 
0

Wenn Ihr id Feld ein Feld mit automatischer Erhöhung ist, und es ist sicher, dass das zu sagen, höchster Wert des id Feldes ist auch der höchste Wert für die date einer Gruppe, dann ist dies eine einfache Lösung:

SELECT b.* 
FROM  (SELECT MAX(id) AS maxid FROM titles GROUP BY group) a 
JOIN  titles b ON a.maxid = b.id 
ORDER BY b.date DESC 
0

die unter mysql query verwendet neuesten aktualisiert/eingefügt Rekord von Tisch zu bekommen .

SELECT * FROM 
(
    select * from `titles` order by `date` desc 
) as tmp_table 
group by `group` 
order by `date` desc 
1

Ich fand dieses Thema über Google, sah aus, als hätte ich das gleiche Problem. Hier ist meine eigene Lösung, wenn, wie ich, Sie nicht Subqueries mag:

-- Create a temporary table like the output 
CREATE TEMPORARY TABLE titles_tmp LIKE titles; 

-- Add a unique key on where you want to GROUP BY 
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`); 

-- Read the result into the tmp_table. Duplicates won't be inserted. 
INSERT IGNORE INTO titles_tmp 
    SELECT * 
    FROM `titles` 
    ORDER BY `date` DESC; 

-- Read the temporary table as output 
SELECT * 
    FROM titles_tmp 
    ORDER BY `group`; 

es eine bessere Leistung. Hier ist, wie die Geschwindigkeit zu erhöhen, wenn die date_column die gleiche Größenordnung wie die auto_increment_one hat (man dann keine ORDER BY-Anweisung muß):

-- Create a temporary table like the output 
CREATE TEMPORARY TABLE titles_tmp LIKE titles; 

-- Add a unique key on where you want to GROUP BY 
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`); 

-- Read the result into the tmp_table, in the natural order. Duplicates will update the temporary table with the freshest information. 
INSERT INTO titles_tmp 
    SELECT * 
    FROM `titles` 

    ON DUPLICATE KEY 
    UPDATE `id` = VALUES(`id`), 
      `date` = VALUES(`date`), 
      `title` = VALUES(`title`); 

-- Read the temporary table as output 
SELECT * 
    FROM titles_tmp 
    ORDER BY `group`; 

Ergebnis:

+----+-------+---------------------+---------+ 
| id | group | date    | title | 
+----+-------+---------------------+---------+ 
| 2 |  1 | 2012-07-26 19:01:20 | Title 2 | 
| 5 |  2 | 2012-07-26 23:59:52 | Title 5 | 
+----+-------+---------------------+---------+ 

Bei großen Tabellen dieser Methode macht ein wichtiger Punkt in Bezug auf die Leistung.

0

die folgende Abfrage verwenden die aktuellste Datensatz aus jeder Gruppe

SELECT 
T1.* FROM 
(SELECT 
    MAX(ID) AS maxID 
FROM 
    T2 
GROUP BY Type) AS aux 
    INNER JOIN 
T2 AS T2 ON T1.ID = aux.maxID ; 

Wo ID ist Ihr Auto-increment-Feld und Typ ist die Art von Datensätzen zu erhalten, die Sie gruppieren wollte durch.

0

MySQL eine stumme Erweiterung von GROUP BY verwendet, die nicht zuverlässig ist, wenn Sie deshalb solche Ergebnisse erhalten möchten, Sie

select id, group, date, title from titles as t where id = 
(select id from titles where group = a.group order by date desc limit 1); 

In dieser Abfrage jedes Mal, wenn die Tabelle für jede Gruppe voll nutzen könnten, so wird gescannt kann das neueste Datum finden. Ich konnte keine bessere Alternative dafür finden. Hoffe, das wird jemandem helfen.