/ / Żądanie SQL do obu odpowiedzi grupowych i pobrania tylko ostatniej linii każdego z nich - mysql

Zapytanie SQL do obu odpowiedzi grupowych i pobranie tylko ostatniego wiersza każdego - mysql

Mam stół bez identyfikatorów. ma 3 kolumny: nazwę komputera, jego status (wł. / wył.) w momencie odpytywania oraz znacznik czasu wstawienia.

jeśli biegnę

select * from computers group by name;

Dostaję linię dla każdego komputera (jest ich 200), ale te linie nie zawsze zawierają najnowszy wpis. Próbowałem

select computers group by name order by timestamp asc;

Ale otrzymuję niespójne odpowiedzi (niektóre ostatnie znaczniki czasu, niektóre stare ... nie wiem dlaczego).

Jest to zasadniczo ten sam problem, co tutaj: SQL: GROUP BY rekordy, a następnie uzyskaj ostatni rekord z każdej grupy?, ale nie mam id do pomocy :(

Odpowiedzi:

1 dla odpowiedzi № 1

Możesz pisać:

SELECT computers.name,
computers.status,
computers.timestamp
FROM ( SELECT name,
MAX(timestamp) AS max_timestamp
FROM computers
GROUP
BY name
) AS t
JOIN computers
ON computers.name = t.name
AND computers.timestamp = t.max_timestamp
;

Powyższe używa tego podzapytania do znalezienia największego timestamp dla każdego name:

SELECT name
MAX(timestamp) AS max_timestamp
FROM computers
GROUP
BY name
;

a następnie zbiera pola z computers którego name i timestamp dopasuj coś, co zwróciło podzapytanie.

Powód, dla którego order by klauzula nie ma żadnego skutku, ponieważ przychodzi zbyt „późno”: jest używana do zamawiania rekordów, które będą zwracane, po tym, jak już ustalono, że będzie Być zwracane. Cytować z § 11.16.3 ”GROUP BY i HAVING z ukrytymi kolumnami ”w MySQL 5.6 Reference Manual w tym temacie:

Serwer może wybrać dowolną wartość z każdegogrupa, więc jeśli nie są takie same, wybrane wartości są nieokreślone. Ponadto na wybór wartości z każdej grupy nie można wpływać przez dodanie ORDER BY klauzula. Sortowanie zestawu wyników następuje po wybraniu wartości i ORDER BY nie wpływa na wartości wybrane przez serwer.

Innym sposobem jest napisanie współzależny podzapytanie i zrezygnuj z GROUP BY całkowicie. To:

SELECT name, status, timestamp
FROM computers AS c1
WHERE NOT EXISTS
( SELECT 1
FROM computers
WHERE name = c1.name
AND timestamp > c1.timestamp
)
;

znajduje wszystkie wiersze w computers to nie zostało zastąpione przez nowsze wiersze tego samego name. To samo podejście można wykonać przy połączeniu:

SELECT c1.name, c1.status, c1.timestamp
FROM computers AS c1
LEFT
OUTER
JOIN computers AS c2
ON c2.name = c1.name
AND c2.timestamp > c1.timestamp
WHERE c2.name IS NULL
;

który jest mniej wyraźny IMHO, ale może działać lepiej.