MySQL: pobierz najnowszy rekord

80

Jak w poniższej tabeli mogę uzyskać tylko najnowszy rekord z id=1kolumny logowania, a nie wszystkie 3 rekordy?

+----+---------------------+---------+
| id | signin              | signout |
+----+---------------------+---------+
|  1 | 2011-12-12 09:27:24 | NULL    |
|  1 | 2011-12-13 09:27:31 | NULL    |
|  1 | 2011-12-14 09:27:34 | NULL    |
|  2 | 2011-12-14 09:28:21 | NULL    |
+----+---------------------+---------+
urok
źródło

Odpowiedzi:

90

Użyj agregatu MAX(signin)pogrupowanego według identyfikatora. Spowoduje to wyświetlenie najnowszych signindla każdego id.

SELECT 
 id, 
 MAX(signin) AS most_recent_signin
FROM tbl
GROUP BY id

Aby uzyskać cały pojedynczy rekord, wykonaj INNER JOINzapytanie względem podzapytania, które zwraca tylko MAX(signin)identyfikator według.

SELECT 
  tbl.id,
  signin,
  signout
FROM tbl
  INNER JOIN (
    SELECT id, MAX(signin) AS maxsign FROM tbl GROUP BY id
  ) ms ON tbl.id = ms.id AND signin = maxsign
WHERE tbl.id=1
Michaela Berkowskiego
źródło
Oto, co zadziałało w oparciu o twoją pierwszą odpowiedź:SELECT id, MAX(signin) FROM tbl GROUP BY id WHERE id=1;
enchance
Próbowałem wdrożyć drugie rozwiązanie (aby uzyskać cały wiersz) w swojej własnej sytuacji, ale zawsze otrzymuję pusty zestaw wyników
rantsh
Odpowiedź @rantsh xQbert miała poprawną wersję tego, co pierwotnie miałem powyżej, ale wolę rozwiązanie, które po prostu zmieniłem.
Michael Berkowski
@MichaelBerkowski chodziło Ci o to, że wolisz moje rozwiązanie? Nie miałbym nic przeciwko uzyskaniu głosu za moją odpowiedź, jeśli tak jest
rantsh
1
@rantsh Ach, nie zauważyłem, że dodałeś coś podobnego do tego, co właśnie zmodyfikowałem, z wyjątkiem via USINGzamiast jawnego ON. Dostałeś +1 :)
Michael Berkowski
83
SELECT *
FROM   tbl
WHERE  id = 1
ORDER  BY signin DESC
LIMIT  1;

Oczywistym wskaźnik będzie na (id), lub indeks wielokolumnowa na (id, signin DESC).

Dogodnie dla tego przypadku MySQL sortuje ostatnieNULL wartości w porządku malejącym. To jest to, czego zazwyczaj potrzebujesz, jeśli mogą istnieć wartości: wiersz z najnowszą wartością niezerową .NULLsignin

Aby NULLnajpierw uzyskać wartości:

ORDER BY signin IS NOT NULL, signin DESC

Związane z:

Standard SQL nie definiuje jawnie domyślnej kolejności sortowania NULLwartości. Zachowanie różni się nieco w różnych systemach RDBMS. Widzieć:

Ale nie to NULLS FIRST/ NULLS LASTklauzule zdefiniowane w standardzie SQL i obsługiwane przez większość dużych RDBMS, ale nie przez MySQL. Widzieć:

Erwin Brandstetter
źródło
5
To najczystszy sposób na zrobienie tego!
karancan
Zastanów się nad utworzeniem indeksu dla kolumny logowania, znacznie przyspieszy to proces
Alexei Tenitski
Użyj SELECT TOP 1 *i usuń LIMIT 1ostatnią linię. jeśli używasz SQL Server. Użyj powyższego, jeśli MySQL lub Postgres.
jaredbaszler
Najczystsze. . . . . . . .
stigzler
Proste i czyste!
Jeremy Swagger
9

Opierając się na odpowiedziach @ xQbert, możesz uniknąć podzapytania ORAZ sprawić, że będzie wystarczająco ogólne, aby filtrować według dowolnego identyfikatora

SELECT id, signin, signout
FROM dTable
INNER JOIN(
  SELECT id, MAX(signin) AS signin
  FROM dTable
  GROUP BY id
) AS t1 USING(id, signin)
rantsh
źródło
Cześć, jak działa to zapytanie i czy jest bardziej wydajne niż odpowiedź xQberta? Oba zapytania są uruchamiane mniej więcej w tym samym czasie i nie rozumiem, jak część zapytania zastępuje to, co zwykle i jest włączone.
ZJS
3
Select [insert your fields here]
from tablename 
where signin = (select max(signin) from tablename where ID = 1)
xQbert
źródło
1
SELECT * FROM (SELECT * FROM tb1 ORDER BY signin DESC) GROUP BY id;
user3044573
źródło
1

Miałem podobny problem. Musiałem uzyskać ostatnią wersję tłumaczenia zawartości strony, innymi słowy - uzyskać ten konkretny rekord, który ma najwyższą liczbę w kolumnie wersji. Więc wybieram wszystkie rekordy uporządkowane według wersji, a następnie biorę pierwszy wiersz z wyniku (za pomocą klauzuli LIMIT).

SELECT *
FROM `page_contents_translations`
ORDER BY version DESC
LIMIT 1
Ales
źródło
1

Prosty sposób na osiągnięcie

Wiem, że to stare pytanie. Możesz też zrobić coś takiego

SELECT * FROM Table WHERE id=1 ORDER BY signin DESC

W powyższym zapytaniu pierwszy rekord będzie najnowszym rekordem.

Tylko dla jednego rekordu możesz użyć czegoś takiego

SELECT top(1) * FROM Table WHERE id=1 ORDER BY signin DESC

Powyższe zapytanie zwróci tylko jeden najnowszy rekord.

Twoje zdrowie!

Ajmal Jamil
źródło