2012-07-27 13 views
9

moim stole titles wygląda następującoMySQL sortując datami z 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 

muszę ostatni wynik z każdej grupy uporządkowanej według daty w kolejności malejącej. Coś takiego

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

Próbowałem

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

ale jestem geting pierwsze wyniki z grup. Podoba Ci się:

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

Co robię źle? Czy to zapytanie będzie bardziej skomplikowane, jeśli użyję LEWEGO JOIN?

+0

Jeśli potrzebujesz tylko dwóch kolumn (np. ID i jego najnowszego znacznika czasu), może to działać: http://stackoverflow.com/a/4448536/722036. Jest ** szybszy ** niż użycie sub-zapytań na ogromnym stole z milionami wierszy. –

Odpowiedz

8

This page był dla mnie bardzo pomocny; nauczyło mnie, jak korzystać z samo łączeń, aby uzyskać max/min/coś-n wierszy na grupę.

W sytuacji, może być stosowana do skutku chcesz tak:

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

Dobrze, jeśli daty są unikalne w grupie to będzie działać (jeśli nie, zobaczysz kilka wierszy dopasuj maksymalną datę w grupie). (Również złe nazewnictwo kolumn, „grupa”, „data” może dać składni błędów i tak specjalnie „grupa”)

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

Innym podejściem jest wykorzystanie zmiennych użytkownika MySQL do identyfikacji „przerwę sterowania "w wartościach group.

Jeśli można żyć z zwracane dodatkowa kolumna, coś jak to będzie działać:

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 

Co to robi jest zamawianie wszystkich wierszy przez group i date w kolejności malejącej. (Podajemy DESC na wszystkich kolumnach w ORDER BY, w przypadku, gdy istnieje indeks na (group,date,id), że MySQL może wykonać "skanowanie wsteczne". Włączenie kolumny id powoduje, że uzyskujemy deterministyczne (powtarzalne) zachowanie, w przypadku gdy istnieje więcej niż jeden wiersz z najnowszą wartością date.) To jest widok śródliniowy o nazwie s.

"Podstęp", którego używamy, polega na porównaniu wartości group z wartością group z poprzedniego wiersza. Ilekroć mamy inną wartość, wiemy, że zaczynamy "nową" grupę, i że ten wiersz jest "ostatnim" wierszem (mamy funkcję IF zwracającą 1). W przeciwnym razie (gdy wartości grupowe są zgodne), nie jest to ostatni wiersz (a funkcja IF zwraca wartość 0).

Następnie odfiltrowujemy wszystkie wiersze, które nie mają tego zestawu latest_in_group jako 1.

Jest możliwe, aby usunąć tę dodatkową kolumnę owijając że zapytanie (jako widoku inline) w innym zapytaniu:

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

Jeśli pole id jest polem autoinkrementacja, a to na pewno powiedzieć, że najwyższa wartość pola id jest również najwyższa jakość za date jakiejkolwiek grupy, to jest proste rozwiązanie:

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

Użyj poniższego zapytania mysql, aby uzyskać najnowszą zaktualizowaną/wstawiony rekord z tabeli .

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

znalazłem ten temat za pośrednictwem Google, wyglądał jak miałem ten sam problem. Oto moje własne rozwiązanie, jeśli, jak ja, nie lubisz podzapytania:

-- 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`; 

Ma to sposób lepszą wydajność. Oto jak zwiększyć prędkość jeśli date_column ma takiej samej kolejności jak w auto_increment_one (wtedy nie trzeba ORDER BY oświadczenie):

-- 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`; 

Wynik:

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

Na dużych tabel metoda ta sprawia, znaczący punkt pod względem wydajności.

0

Użyj następującej kwerendy, aby uzyskać najnowszą płytę z każdej grupy

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 ; 

gdzie id to pole automatycznego przyrostu i typu jest rodzaj ewidencji, chciałeś przez grupę.

0

MySQL używa niemy przedłużenie GROUP BY które nie są wiarygodne, jeśli chcesz uzyskać takie rezultaty zatem można użyć

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); 

W tym zapytaniu każdym razem, gdy stół jest skanowany pełny dla każdej grupy, dlatego można znaleźć najnowszą datę. Nie mogłem znaleźć lepszego zastępcy. Mam nadzieję, że to pomoże komuś.