SQL wybierz tylko wiersze z maksymalną wartością w kolumnie [duplikat]

chcesz poprawić ten post? podaj szczegółowe odpowiedzi na to pytanie, w tym cytaty i wyjaśnienie, dlaczego Twoja odpowiedź jest prawidłowa. Odpowiedzi bez wystarczającej ilości szczegółów mogą być edytowane lub usuwane. to pytanie ma już odpowiedzi tutaj : pobieranie ostatniego rekordu w każdej grupie-MySQL (29 odpowiedzi) Zamknięty 1 rok temu.

Mam ta tabela dla dokumentów (wersja uproszczona tutaj):

+------+-------+--------------------------------------+
| id   | rev   | content                              |
+------+-------+--------------------------------------+
| 1    | 1     | ...                                  |
| 2    | 1     | ...                                  |
| 1    | 2     | ...                                  |
| 1    | 3     | ...                                  |
+------+-------+--------------------------------------+

Jak wybrać jeden wiersz na id i tylko największe obroty?
Przy powyższych danych wynik powinien zawierać dwa wiersze: [1, 3, ...] i [2, 1, ..]. Używam MySQL.

Obecnie używam sprawdzeń w pętli while do wykrywania i nadpisywania starych obrotów z resultset. Ale czy jest to jedyna metoda osiągnięcia rezultatu? Czy nie ma rozwiązania SQL?

Update
Jako odpowiedzi sugerują, że istnieje jest rozwiązanie SQL, a tutaj demo sqlfiddle .

Update 2
Zauważyłem po dodaniu powyższego sqlfiddle , szybkość, z jaką pytanie jest upvoted przekroczyła szybkość upvote odpowiedzi. Nie taki był zamiar! Skrzypek opiera się na odpowiedziach, zwłaszcza na zaakceptowanej odpowiedzi.

Author: Rick James, 2011-10-12

27 answers

Na pierwszy rzut oka...

Wystarczy GROUP BY klauzula z MAX funkcją zbiorczą:

SELECT id, MAX(rev)
FROM YourTable
GROUP BY id
To nigdy nie jest takie proste, prawda?

Właśnie zauważyłem, że potrzebujesz kolumny content.

Jest to bardzo częste pytanie w SQL: znajdź całe dane dla wiersza z pewną wartością maksymalną w kolumnie dla jakiegoś identyfikatora grupy. Często to słyszałem w trakcie mojej kariery. Właściwie to było to jedno z pytań, na które odpowiadałem podczas rozmowy technicznej w mojej obecnej pracy.

Jest to tak powszechne, że społeczność StackOverflow stworzyła pojedynczy znacznik, aby poradzić sobie z takimi pytaniami: greatest-n-per-group.

Zasadniczo masz dwa podejścia do rozwiązania tego problemu:

Łączenie z prostym group-identifier, max-value-in-group Sub-query

W tym podejściu najpierw znajdziesz group-identifier, max-value-in-group (już rozwiązany powyżej) w zapytaniu podrzędnym. Następnie dołączysz tabelę do zapytania podrzędnego z równością zarówno group-identifier jak i max-value-in-group:

SELECT a.id, a.rev, a.contents
FROM YourTable a
INNER JOIN (
    SELECT id, MAX(rev) rev
    FROM YourTable
    GROUP BY id
) b ON a.id = b.id AND a.rev = b.rev

Left Joining z self, tweaking warunków łączenia i filtrów

W tym podejściu, lewo join tabeli z siebie. Równość idzie w group-identifier. Następnie 2 mądre ruchy:

  1. drugi warunek połączenia ma wartość po lewej stronie mniejszą niż wartość po prawej
  2. kiedy wykonasz Krok 1, wiersz(Y), który faktycznie ma wartość maksymalną, będzie miał NULL po prawej stronie (jest to LEFT JOIN, pamiętasz?). Następnie filtrujemy wynik połączenia, pokazując tylko wiersze, w których znajduje się prawa strona NULL.

Więc kończysz z:

SELECT a.*
FROM YourTable a
LEFT OUTER JOIN YourTable b
    ON a.id = b.id AND a.rev < b.rev
WHERE b.id IS NULL;

Podsumowanie

Oba podejścia przynoszą dokładnie ten sam rezultat.

Jeśli masz dwa wiersze z max-value-in-group dla group-identifier, oba wiersze będą w wyniku w obu podejściach.

Oba podejścia są kompatybilne z SQL ANSI, dzięki czemu będą działać z Twoimi ulubionymi RDBMS, niezależnie od jego "smaku".

Oba podejścia są również przyjazne dla wydajności, jednak przebieg może się różnić (RDBMS, struktura DB, indeksy itp.). Więc kiedy wybierzesz jedno podejście nad drugim, benchmark. I upewnij się, że wybierzesz ten, który ma dla Ciebie największy sens.

 2123
Author: Adriano Carneiro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-13 12:16:45

Preferuję użycie jak najmniejszej ilości kodu...

Możesz to zrobić używając IN spróbuj tego:

SELECT * 
FROM t1 WHERE (id,rev) IN 
( SELECT id, MAX(rev)
  FROM t1
  GROUP BY id
)
Według mnie jest to mniej skomplikowane... łatwiejsze do odczytania i utrzymania.
 293
Author: Kevin Burton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-16 13:08:50

Jestem oszołomiony, że żadna odpowiedź nie oferuje rozwiązania funkcji okna SQL:

SELECT a.id, a.rev, a.contents
  FROM (SELECT id, rev, contents,
               ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rank
          FROM YourTable) a
 WHERE a.rank = 1 

Dodane w standardzie SQL ANSI/ISO Standard SQL: 2003 i Później rozszerzone o ANSI/ISO Standard SQL: 2008, funkcje window (lub windowing) są teraz dostępne u wszystkich głównych dostawców. Istnieje więcej typów funkcji rank dostępnych w przypadku remisu: RANK, DENSE_RANK, PERSENT_RANK.

 107
Author: topchef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-14 23:16:43

Jeszcze innym rozwiązaniem jest użycie skorelowanej subquery:

select yt.id, yt.rev, yt.contents
    from YourTable yt
    where rev = 
        (select max(rev) from YourTable st where yt.id=st.id)

Posiadanie indeksu w (id,rev) powoduje, że zapytanie podrzędne jest prawie proste...

Poniżej znajdują się porównania do rozwiązań w odpowiedzi @AdrianCarneiro (subquery, leftjoin), opartych na pomiarach MySQL z tabelą InnoDB o wielkości ~1mln rekordów, wielkość grupy wynosi: 1-3.

Podczas gdy Pełne skanowanie tabeli subquery / leftjoin/skorelowane czasy odnoszą się do siebie jako 6/8/9, jeśli chodzi o bezpośrednie wyszukiwanie lub wsad (id in (1,2,3)), subquery jest znacznie wolniejsze niż pozostałe (z powodu ponownego uruchomienia subquery). Jednak nie mogłem odróżnić leftjoin od skorelowanych rozwiązań w szybkości.

Ostatnia uwaga, ponieważ leftjoin tworzy N * (n+1)/2 łączy się w grupy, na jego wydajność może mieć duży wpływ wielkość grup...

 88
Author: Vajk Hermecz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-23 14:16:11

Nie mogę ręczyć za wydajność, ale oto sztuczka inspirowana ograniczeniami Microsoft Excel. Ma kilka dobrych cech

GOOD STUFF

  • powinno wymusić powrót tylko jednego "rekordu maksymalnego", nawet jeśli jest remis (czasami przydatny)
  • nie wymaga połączenia

Podejście

Jest trochę brzydki i wymaga, aby wiedzieć coś o zakresie ważnych wartości rev kolumna. Niech Zakładamy, że znamy rev kolumna jest liczbą od 0,00 do 999 włącznie z dziesiętnymi, ale zawsze będą tylko dwie cyfry na prawo od punktu dziesiętnego (np. 34,17 będzie prawidłową wartością).

Sednem sprawy jest to, że tworzysz pojedynczą kolumnę syntetyczną za pomocą łańcucha łączącego / pakującego podstawowe pole porównania wraz z żądanymi danymi. W ten sposób możesz wymusić funkcję SQL MAX() aggregate, aby zwróciła wszystkie dane (ponieważ ma zapakowane w jedną kolumnę). Następnie musisz rozpakować dane.

Oto jak wygląda powyższy przykład, napisany w SQL

SELECT id, 
       CAST(SUBSTRING(max(packed_col) FROM 2 FOR 6) AS float) as max_rev,
       SUBSTRING(max(packed_col) FROM 11) AS content_for_max_rev 
FROM  (SELECT id, 
       CAST(1000 + rev + .001 as CHAR) || '---' || CAST(content AS char) AS packed_col
       FROM yourtable
      ) 
GROUP BY id

Pakowanie zaczyna się od wymuszenia rev kolumna ma być liczbą o znanej długości znaków niezależnie od wartości rev tak, że na przykład

  • 3.2.1003.201
  • 57.1057.001
  • 923.88 1923.881

If you do it right, porównywanie łańcuchów dwóch liczb powinno dawać takie same "max" jak porównywanie liczb dwóch liczb i łatwo jest przekonwertować z powrotem na liczbę oryginalną za pomocą funkcji substring(która jest dostępna w takiej czy innej formie praktycznie wszędzie).

 46
Author: David Foster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-30 06:02:30

Unikalne Identyfikatory? Tak! Unikalne identyfikatory!

Jednym z najlepszych sposobów na stworzenie MySQL DB jest aby każdy id AUTOINCREMENT (źródło MySQL.com). pozwala to na wiele zalet, zbyt wiele do pokrycia tutaj. Problem z pytaniem polega na tym, że jego przykład ma duplikaty identyfikatorów. Pomija to ogromne zalety unikalnych identyfikatorów, a jednocześnie jest mylące dla tych, którzy już o tym wiedzą.

Najczystszy Roztwór

DB Fiddle

Nowsze wersje MySQL pochodzą z ONLY_FULL_GROUP_BY włączone domyślnie, a wiele z rozwiązań tutaj będzie fail w testowaniu z tym warunkiem.

Mimo to, możemy po prostu wybrać DISTINCT someuniquefield, MAX( / align = "left" / ), ( * somethirdfield ), itp. i nie martw się zrozumieniem wyniku lub sposobu działania zapytania:

SELECT DISTINCT t1.id, MAX(t1.rev), MAX(t2.content)
FROM Table1 AS t1
JOIN Table1 AS t2 ON t2.id = t1.id AND t2.rev = (
    SELECT MAX(rev) FROM Table1 t3 WHERE t3.id = t1.id
)
GROUP BY t1.id;
  • SELECT DISTINCT Table1.id, max(Table1.rev), max(Table2.content) : Return DISTINCT somefield, MAX() some otherfield, The last MAX() jest zbędny, ponieważ Wiem, że to tylko jeden wiersz, ale jest wymagany przez zapytanie.
  • FROM Employee : tabela przeszukiwana.
  • JOIN Table1 AS Table2 ON Table2.rev = Table1.rev : Dołącz do drugiej tabeli na pierwszej, ponieważ, musimy uzyskać max (table1.rev) ' s comment.
  • GROUP BY Table1.id: wymusić, aby zwrócony wynik był sortowany w górę, rząd wynagrodzeń każdego pracownika.

Zauważ, że ponieważ" treść "była"..."w pytaniu OP nie ma możliwości sprawdzenia, czy to działa. Więc zmieniłem to na "..","..b", więc my można teraz zobaczyć, że wyniki są poprawne:

id  max(Table1.rev) max(Table2.content)
1   3   ..d
2   1   ..b

dlaczego jest czysty? DISTINCT(), MAX(), itd., wszystkie świetnie wykorzystują indeksy MySQL. Tak będzie szybciej. Lub będzie to znacznie szybsze, jeśli masz indeksowanie i porównujesz je z zapytaniem, które patrzy na wszystkie wiersze.

Oryginalne Rozwiązanie

Z ONLY_FULL_GROUP_BY wyłączonym, możemy używać still use GROUP BY, ale wtedy używamy go tylko na pensji, a nie na id:

SELECT *
FROM
    (SELECT *
    FROM Employee
    ORDER BY Salary DESC)
AS employeesub
GROUP BY employeesub.Salary;
  • SELECT * : Return all pola.
  • FROM Employee : tabela przeszukiwana.
  • (SELECT *...) subquery: zwracają wszystkie osoby, posortowane według wynagrodzenia.
  • GROUP BY employeesub.Salary: wymusić, aby zwrócony wynik był sortowany od góry, rząd wynagrodzeń każdego pracownika.

Unique-Row Solution

Zwróć uwagę na definicję relacyjnej bazy danych : "każdy wiersz w tabeli ma swój unikalny klucz."Oznaczałoby to, że w przykładzie pytania id musiałoby być unikalne, a w takim przypadku możemy po prostu zrobić :

SELECT *
FROM Employee
WHERE Employee.id = 12345
ORDER BY Employee.Salary DESC
LIMIT 1

Miejmy nadzieję, że jest to rozwiązanie, które rozwiązuje problem i pomaga wszystkim lepiej zrozumieć, co dzieje się w DB.

 37
Author: HoldOffHunger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-02 01:31:37

Coś takiego?

SELECT yourtable.id, rev, content
FROM yourtable
INNER JOIN (
    SELECT id, max(rev) as maxrev
    FROM yourtable
    GROUP BY id
) AS child ON (yourtable.id = child.id) AND (yourtable.rev = maxrev)
 23
Author: Marc B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-02 16:11:46

Innym sposobem wykonania zadania jest użycie MAX() funkcji analitycznej w klauzuli over PARTITION

SELECT t.*
  FROM
    (
    SELECT id
          ,rev
          ,contents
          ,MAX(rev) OVER (PARTITION BY id) as max_rev
      FROM YourTable
    ) t
  WHERE t.rev = t.max_rev 

Inne ROW_NUMBER() rozwiązanie nad partycją już udokumentowane w tym poście to

SELECT t.*
  FROM
    (
    SELECT id
          ,rev
          ,contents
          ,ROW_NUMBER() OVER (PARTITION BY id ORDER BY rev DESC) rank
      FROM YourTable
    ) t
  WHERE t.rank = 1 
[[10]} Ten 2 SELECT działa dobrze na Oracle 10g.

MAX () rozwiązanie działa zdecydowanie szybciej niż ROW_NUMBER() rozwiązanie ponieważ MAX() złożoność jest O(n) podczas gdy ROW_NUMBER() złożoność jest minimalna O(n.log(n)) gdzie n reprezentuje liczbę rekordów w tabeli !

 13
Author: schlebe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-24 09:55:37

Lubię używać rozwiązania NOT EXIST na ten problem:

SELECT 
  id, 
  rev
  -- you can select other columns here
FROM YourTable t
WHERE NOT EXISTS (
   SELECT * FROM YourTable t WHERE t.id = id AND rev > t.rev
)

Spowoduje to wybranie wszystkich rekordów z maksymalną wartością w grupie i pozwoli na wybranie innych kolumn.

 11
Author: Bulat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-26 06:18:06
SELECT *
FROM Employee
where Employee.Salary in (select max(salary) from Employee group by Employe_id)
ORDER BY Employee.Salary
 7
Author: guru008,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-22 18:30:12

Trzecie rozwiązanie, o którym prawie nigdy nie wspominałem, jest specyficzne dla MySQL i wygląda tak:

SELECT id, MAX(rev) AS rev
 , 0+SUBSTRING_INDEX(GROUP_CONCAT(numeric_content ORDER BY rev DESC), ',', 1) AS numeric_content
FROM t1
GROUP BY id

Tak wygląda okropnie (konwersja na string i back itp.), ale z mojego doświadczenia wynika, że jest to zwykle szybsze od innych rozwiązań. Może to tylko dla moich przypadków użycia, ale używałem go na stołach z milionami rekordów i wieloma unikalnymi identyfikatorami. Może dlatego, że MySQL jest dość kiepski w optymalizacji innych rozwiązań(przynajmniej w 5.0 dni, kiedy wpadłem na to rozwiązanie).

One ważne jest to, że GROUP_CONCAT ma maksymalną długość Dla ciągu, który może budować. Prawdopodobnie chcesz zwiększyć ten limit, ustawiając zmienną group_concat_max_len. Pamiętaj, że będzie to limit skalowania, jeśli masz dużą liczbę wierszy.

W każdym razie powyższe nie działa bezpośrednio, jeśli twoje pole zawartości jest już tekstem. W takim przypadku prawdopodobnie chcesz użyć innego separatora, np. \0. Możesz również szybciej napotkać group_concat_max_len limit.

 6
Author: Jannes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-10 11:57:00

Myślę, że chcesz tego?

select * from docs where (id, rev) IN (select id, max(rev) as rev from docs group by id order by id)  

SQL : Sprawdź tutaj

 6
Author: Abhishek Rana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-29 11:00:18

Nie mySQL, ale dla innych osób szukających tego pytania i korzystających z SQL, innym sposobem rozwiązania problemu greatest-n-per-group jest użycie Cross Apply w MS SQL

WITH DocIds AS (SELECT DISTINCT id FROM docs)

SELECT d2.id, d2.rev, d2.content
FROM DocIds d1
CROSS APPLY (
  SELECT Top 1 * FROM docs d
  WHERE d.id = d1.id
  ORDER BY rev DESC
) d2

Oto przykład w SqlFiddle

 5
Author: KyleMit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-17 14:55:51

Ponieważ jest to najbardziej popularne pytanie w odniesieniu do tego problemu, zamieszczę ponownie kolejną odpowiedź na to pytanie również tutaj:

Wygląda na to, że jest prostszy sposób na to (ale tylko w MySQL):

select *
from (select * from mytable order by id, rev desc ) x
group by id

Proszę o odpowiedź użytkownika Bohemian w to pytanie za udzielenie tak zwięzłej i eleganckiej odpowiedzi na ten problem.

Edit: chociaż to rozwiązanie działa dla wielu osób, może nie być stabilne na dłuższą metę, ponieważ MySQL nie gwarantuje, że polecenie GROUP BY zwróci znaczące wartości dla kolumn spoza listy GROUP BY. Więc korzystaj z tego rozwiązania na własne ryzyko!

 5
Author: Yuriy Nakonechnyy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-18 20:42:23

Użyłbym tego:

select t.*
from test as t
join
   (select max(rev) as rev
    from test
    group by id) as o
on o.rev = t.rev

Subquery SELECT nie jest zbyt wydajne, ale w klauzuli JOIN wydaje się być użyteczna. Nie jestem ekspertem w optymalizacji zapytań, ale próbowałem w MySQL, PostgreSQL, FireBird i działa bardzo dobrze.

Można używać tego schematu w wielu połączeniach i z klauzulą WHERE. Jest to mój przykład pracy (rozwiązanie identycznego do twojego problemu z tabelą "firmy"):

select *
from platnosci as p
join firmy as f
on p.id_rel_firmy = f.id_rel
join (select max(id_obj) as id_obj
      from firmy
      group by id_rel) as o
on o.id_obj = f.id_obj and p.od > '2014-03-01'

Jest pytany na tablicach mających tak wiele rekordów, że zajmuje mniej niż 0,01 sekundy na naprawdę niezbyt mocnej maszynie.

Nie używałbym klauzuli in (Jak to jest wspomniane gdzieś powyżej). IN jest podane do użycia z krótkimi listami constans, a nie jako filtr zapytań zbudowany na subquery. Dzieje się tak dlatego, że zapytania podrzędne w IN są wykonywane dla każdego zeskanowanego rekordu, który może wykonać zapytanie zajmując bardzo loooong czasu.

 4
Author: Marek Wysmułek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-04 18:12:10

A może tak:

SELECT all_fields.*  
FROM (SELECT id, MAX(rev) FROM yourtable GROUP BY id) AS max_recs  
LEFT OUTER JOIN yourtable AS all_fields 
ON max_recs.id = all_fields.id
 4
Author: inor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-29 15:51:43

Jeśli masz wiele pól w instrukcji select i chcesz uzyskać najnowszą wartość dla wszystkich tych pól za pomocą zoptymalizowanego kodu:

select * from
(select * from table_name
order by id,rev desc) temp
group by id 
 3
Author: seahawk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-04 05:33:22

To rozwiązanie sprawia, że tylko jeden wybór z YourTable, dlatego jest szybszy. Działa tylko dla MySQL i SQLite (dla SQLite Usuń DESC) zgodnie z testem na sqlfiddle.com. może da się go dostosować do pracy na innych językach, których nie znam.

SELECT *
FROM ( SELECT *
       FROM ( SELECT 1 as id, 1 as rev, 'content1' as content
              UNION
              SELECT 2, 1, 'content2'
              UNION
              SELECT 1, 2, 'content3'
              UNION
              SELECT 1, 3, 'content4'
            ) as YourTable
       ORDER BY id, rev DESC
   ) as YourTable
GROUP BY id
 2
Author: plavozont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-17 08:28:23

Oto dobry sposób na to

Użyj następującego kodu:

with temp as  ( 
select count(field1) as summ , field1
from table_name
group by field1 )
select * from temp where summ = (select max(summ) from temp)
 2
Author: shay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-07 12:11:59

Lubię to robić poprzez ranking rekordów według jakiejś kolumny. W tym przypadku wartości rank rev pogrupowane według id. Ci z wyższymi rev będą mieli niższe rankingi. Tak więc najwyższy rev będzie miał rangę 1.

select id, rev, content
from
 (select
    @rowNum := if(@prevValue = id, @rowNum+1, 1) as row_num,
    id, rev, content,
    @prevValue := id
  from
   (select id, rev, content from YOURTABLE order by id asc, rev desc) TEMP,
   (select @rowNum := 1 from DUAL) X,
   (select @prevValue := -1 from DUAL) Y) TEMP
where row_num = 1;

Nie jestem pewien, czy wprowadzenie zmiennych spowalnia całość. Ale przynajmniej nie pytam dwa razy.

 2
Author: user5124980,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-16 18:52:31

Posortowano pole rev w odwrotnej kolejności, a następnie pogrupowano według id, które dało pierwszy wiersz każdej grupy, który ma najwyższą wartość rev.

SELECT * FROM (SELECT * FROM table1 ORDER BY id, rev DESC) X GROUP BY X.id;

Testowane w http://sqlfiddle.com / z następującymi danymi

CREATE TABLE table1
    (`id` int, `rev` int, `content` varchar(11));

INSERT INTO table1
    (`id`, `rev`, `content`)
VALUES
    (1, 1, 'One-One'),
    (1, 2, 'One-Two'),
    (2, 1, 'Two-One'),
    (2, 2, 'Two-Two'),
    (3, 2, 'Three-Two'),
    (3, 1, 'Three-One'),
    (3, 3, 'Three-Three')
;

Dało to następujący wynik w MySql 5.5 i 5.6

id  rev content
1   2   One-Two
2   2   Two-Two
3   3   Three-Two
 2
Author: blokeish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 03:14:18

Oto inne rozwiązanie mam nadzieję, że komuś pomoże

Select a.id , a.rev, a.content from Table1 a
inner join 
(SELECT id, max(rev) rev FROM Table1 GROUP BY id) x on x.id =a.id and x.rev =a.rev
 2
Author: Abdul Samad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-20 10:10:35

Żadna z tych odpowiedzi nie zadziałała.

To mi się udało.
with score as (select max(score_up) from history)
select history.* from score, history where history.score_up = score.max
 2
Author: qaisjp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-13 18:19:20

Oto inne rozwiązanie pobierania rekordów tylko z polem, które ma maksymalną wartość dla tego pola. To działa dla sql400, który jest platformą, na której pracuję. W tym przykładzie rekordy z maksymalną wartością w polu FIELD5 zostaną pobrane za pomocą następującego polecenia SQL.

SELECT A.KEYFIELD1, A.KEYFIELD2, A.FIELD3, A.FIELD4, A.FIELD5
  FROM MYFILE A
 WHERE RRN(A) IN
   (SELECT RRN(B) 
      FROM MYFILE B
     WHERE B.KEYFIELD1 = A.KEYFIELD1 AND B.KEYFIELD2 = A.KEYFIELD2
     ORDER BY B.FIELD5 DESC
     FETCH FIRST ROW ONLY)
 2
Author: Cesar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-17 00:18:19

Wyjaśnienie

To nie jest czysty SQL. To będzie używać SQLAlchemy ORM.

Przyszedłem tutaj szukając pomocy SQLAlchemy, więc powtórzę odpowiedź Adriana Carneiro z wersją Pythona/SQLAlchemy, a konkretnie zewnętrzną częścią join.

To zapytanie odpowiada na pytanie:

"Czy możesz mi zwrócić rekordy z tej grupy rekordów (na podstawie tego samego id), które mają najwyższy numer wersji".

To pozwala mi powielić rekord, zaktualizuj go, zwiększ jego numer wersji i miej kopię starej wersji w taki sposób, że mogę pokazać zmiany w czasie.

Kod

MyTableAlias = aliased(MyTable)
newest_records = appdb.session.query(MyTable).select_from(join(
    MyTable, 
    MyTableAlias, 
    onclause=and_(
        MyTable.id == MyTableAlias.id,
        MyTable.version_int < MyTableAlias.version_int
    ),
    isouter=True
    )
).filter(
    MyTableAlias.id  == None,
).all()

Przetestowano na bazie danych PostgreSQL.

 1
Author: Ian A McElhenny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-22 15:18:26

Użyłem poniższego, aby rozwiązać własny problem. Najpierw utworzyłem tabelę tymczasową i wstawiłem wartość max rev na unikalny identyfikator.

CREATE TABLE #temp1
(
    id varchar(20)
    , rev int
)
INSERT INTO #temp1
SELECT a.id, MAX(a.rev) as rev
FROM 
    (
        SELECT id, content, SUM(rev) as rev
        FROM YourTable
        GROUP BY id, content
    ) as a 
GROUP BY a.id
ORDER BY a.id

Następnie dołączyłem te maksymalne wartości (#temp1) do wszystkich możliwych kombinacji id/content. W ten sposób naturalnie odfiltrowuję Nie-maksymalne kombinacje id/content i pozostaję z jedynymi wartościami max rev dla każdej z nich.

SELECT a.id, a.rev, content
FROM #temp1 as a
LEFT JOIN
    (
        SELECT id, content, SUM(rev) as rev
        FROM YourTable
        GROUP BY id, content
    ) as b on a.id = b.id and a.rev = b.rev
GROUP BY a.id, a.rev, b.content
ORDER BY a.id
 0
Author: Richard Ball,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-05 10:51:51

Możesz dokonać wyboru bez łączenia, gdy połączysz rev i id w jedną maxRevId wartość dla MAX(), a następnie podzielisz ją z powrotem na oryginalne wartości:

SELECT maxRevId & ((1 << 32) - 1) as id, maxRevId >> 32 AS rev
FROM (SELECT MAX(((rev << 32) | id)) AS maxRevId
      FROM YourTable
      GROUP BY id) x;

Jest to szczególnie szybkie, gdy istnieje złożone połączenie zamiast pojedynczej tabeli. Przy tradycyjnym podejściu połączenie złożone odbywałoby się dwukrotnie.

Powyższa kombinacja jest prosta Z FUNKCJAMI bitowymi, gdy rev i idINT UNSIGNED (32-bitowe), a łączna wartość pasuje do BIGINT UNSIGNED (64-bitowe). Gdy id & rev są większe niż wartości 32-bitowe lub złożone z wielu kolumn, musisz połączyć wartość w np. wartość binarną z odpowiednim wypełnieniem dla MAX().

 0
Author: zovio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-17 09:08:22