Как я могу выбрать строки С MAX (значение столбца), отличные от другого столбца в SQL?
мой стол:
id home datetime player resource
---|-----|------------|--------|---------
1 | 10 | 04/03/2009 | john | 399
2 | 11 | 04/03/2009 | juliet | 244
5 | 12 | 04/03/2009 | borat | 555
3 | 10 | 03/03/2009 | john | 300
4 | 11 | 03/03/2009 | juliet | 200
6 | 12 | 03/03/2009 | borat | 500
7 | 13 | 24/12/2008 | borat | 600
8 | 13 | 01/01/2009 | borat | 700
мне нужно выбрать каждый отдельный home
удерживая максимальное значение datetime
.
результат будет такой:
id home datetime player resource
---|-----|------------|--------|---------
1 | 10 | 04/03/2009 | john | 399
2 | 11 | 04/03/2009 | juliet | 244
5 | 12 | 04/03/2009 | borat | 555
8 | 13 | 01/01/2009 | borat | 700
Я пробовал:
-- 1 ..by the MySQL manual:
SELECT DISTINCT
home,
id,
datetime AS dt,
player,
resource
FROM topten t1
WHERE datetime = (SELECT
MAX(t2.datetime)
FROM topten t2
GROUP BY home)
GROUP BY datetime
ORDER BY datetime DESC
не работает. Результирующий набор имеет 130 строк, хотя база данных содержит 187.
Результат включает в себя некоторые дубликаты home
.
-- 2 ..join
SELECT
s1.id,
s1.home,
s1.datetime,
s1.player,
s1.resource
FROM topten s1
JOIN (SELECT
id,
MAX(datetime) AS dt
FROM topten
GROUP BY id) AS s2
ON s1.id = s2.id
ORDER BY datetime
Неа. Дает все записи.
-- 3 ..something exotic:
С различные результаты.
17 ответов:
ты так близко! Все, что вам нужно сделать, это выбрать дом и его максимальное время даты, а затем присоединиться к
topten
таблица на обоих полях:SELECT tt.* FROM topten tt INNER JOIN (SELECT home, MAX(datetime) AS MaxDateTime FROM topten GROUP BY home) groupedtt ON tt.home = groupedtt.home AND tt.datetime = groupedtt.MaxDateTime
здесь идет -ЭТО версия:
-- Test data DECLARE @TestTable TABLE (id INT, home INT, date DATETIME, player VARCHAR(20), resource INT) INSERT INTO @TestTable SELECT 1, 10, '2009-03-04', 'john', 399 UNION SELECT 2, 11, '2009-03-04', 'juliet', 244 UNION SELECT 5, 12, '2009-03-04', 'borat', 555 UNION SELECT 3, 10, '2009-03-03', 'john', 300 UNION SELECT 4, 11, '2009-03-03', 'juliet', 200 UNION SELECT 6, 12, '2009-03-03', 'borat', 500 UNION SELECT 7, 13, '2008-12-24', 'borat', 600 UNION SELECT 8, 13, '2009-01-01', 'borat', 700 -- Answer SELECT id, home, date, player, resource FROM (SELECT id, home, date, player, resource, RANK() OVER (PARTITION BY home ORDER BY date DESC) N FROM @TestTable )M WHERE N = 1 -- and if you really want only home with max date SELECT T.id, T.home, T.date, T.player, T.resource FROM @TestTable T INNER JOIN ( SELECT TI.id, TI.home, TI.date, RANK() OVER (PARTITION BY TI.home ORDER BY TI.date) N FROM @TestTable TI WHERE TI.date IN (SELECT MAX(TM.date) FROM @TestTable TM) )TJ ON TJ.N = 1 AND T.id = TJ.id
EDIT
К сожалению, в MySQL нет функции RANK() OVER.
Но его можно эмулировать, см. эмуляция аналитических (АКА ранжирование) функций с MySQL.
Так это MySQL версия:SELECT id, home, date, player, resource FROM TestTable AS t1 WHERE (SELECT COUNT(*) FROM TestTable AS t2 WHERE t2.home = t1.home AND t2.date > t1.date ) = 0
быстрый
MySQL
решение, без внутренних запросов, и безGROUP BY
:SELECT m.* -- get the row that contains the max value FROM topten m -- "m" from "max" LEFT JOIN topten b -- "b" from "bigger" ON m.home = b.home -- match "max" row with "bigger" row by `home` AND m.datetime < b.datetime -- want "bigger" than "max" WHERE b.datetime IS NULL -- keep only if there is no bigger than max
объяснение:
Присоединяйтесь к таблице с помощью
Это будет работать даже если у вас две или более строк для каждого
home
равнымиDATETIME
' s:SELECT id, home, datetime, player, resource FROM ( SELECT ( SELECT id FROM topten ti WHERE ti.home = t1.home ORDER BY ti.datetime DESC LIMIT 1 ) lid FROM ( SELECT DISTINCT home FROM topten ) t1 ) ro, topten t2 WHERE t2.id = ro.lid
Я думаю, это даст вам желаемый результат:
SELECT home, MAX(datetime) FROM my_table GROUP BY home
но если вам нужны и другие столбцы, просто сделайте соединение с исходной таблицей (проверьте
Michael La Voie
ответ)С наилучшими пожеланиями.
поскольку люди, похоже, продолжают работать в этой теме (дата комментария колеблется от 1,5 года), это не намного проще:
SELECT * FROM (SELECT * FROM topten ORDER BY datetime DESC) tmp GROUP BY home
агрегатные функции не требуются...
Ура.
вы также можете попробовать это, и для больших таблиц производительность запросов будет лучше. Это работает, когда есть не более двух записей для каждого дома и их даты отличаются. Лучший общий запрос MySQL - это один из Michael La Voie выше.
SELECT t1.id, t1.home, t1.date, t1.player, t1.resource FROM t_scores_1 t1 INNER JOIN t_scores_1 t2 ON t1.home = t2.home WHERE t1.date > t2.date
или в случае Postgres или тех dbs, которые предоставляют аналитические функции, попробуйте
SELECT t.* FROM (SELECT t1.id, t1.home, t1.date, t1.player, t1.resource , row_number() over (partition by t1.home order by t1.date desc) rw FROM topten t1 INNER JOIN topten t2 ON t1.home = t2.home WHERE t1.date > t2.date ) t WHERE t.rw = 1
это работает на Oracle:
with table_max as( select id , home , datetime , player , resource , max(home) over (partition by home) maxhome from table ) select id , home , datetime , player , resource from table_max where home = maxhome
SELECT tt.* FROM TestTable tt INNER JOIN ( SELECT coord, MAX(datetime) AS MaxDateTime FROM rapsa GROUP BY krd ) groupedtt ON tt.coord = groupedtt.coord AND tt.datetime = groupedtt.MaxDateTime
попробуйте это для SQL Server:
WITH cte AS ( SELECT home, MAX(year) AS year FROM Table1 GROUP BY home ) SELECT * FROM Table1 a INNER JOIN cte ON a.home = cte.home AND a.year = cte.year
SELECT c1, c2, c3, c4, c5 FROM table1 WHERE c3 = (select max(c3) from table) SELECT * FROM table1 WHERE c3 = (select max(c3) from table1)
вот версия MySQL, которая печатает только одну запись, где есть дубликаты MAX(datetime) в группе.
вы можете проверить здесь http://www.sqlfiddle.com/#!2/0a4ae/1
Пример Данных
mysql> SELECT * from topten; +------+------+---------------------+--------+----------+ | id | home | datetime | player | resource | +------+------+---------------------+--------+----------+ | 1 | 10 | 2009-04-03 00:00:00 | john | 399 | | 2 | 11 | 2009-04-03 00:00:00 | juliet | 244 | | 3 | 10 | 2009-03-03 00:00:00 | john | 300 | | 4 | 11 | 2009-03-03 00:00:00 | juliet | 200 | | 5 | 12 | 2009-04-03 00:00:00 | borat | 555 | | 6 | 12 | 2009-03-03 00:00:00 | borat | 500 | | 7 | 13 | 2008-12-24 00:00:00 | borat | 600 | | 8 | 13 | 2009-01-01 00:00:00 | borat | 700 | | 9 | 10 | 2009-04-03 00:00:00 | borat | 700 | | 10 | 11 | 2009-04-03 00:00:00 | borat | 700 | | 12 | 12 | 2009-04-03 00:00:00 | borat | 700 | +------+------+---------------------+--------+----------+
версия MySQL с пользовательской переменной
SELECT * FROM ( SELECT ord.*, IF (@prev_home = ord.home, 0, 1) AS is_first_appear, @prev_home := ord.home FROM ( SELECT t1.id, t1.home, t1.player, t1.resource FROM topten t1 INNER JOIN ( SELECT home, MAX(datetime) AS mx_dt FROM topten GROUP BY home ) x ON t1.home = x.home AND t1.datetime = x.mx_dt ORDER BY home ) ord, (SELECT @prev_home := 0, @seq := 0) init ) y WHERE is_first_appear = 1; +------+------+--------+----------+-----------------+------------------------+ | id | home | player | resource | is_first_appear | @prev_home := ord.home | +------+------+--------+----------+-----------------+------------------------+ | 9 | 10 | borat | 700 | 1 | 10 | | 10 | 11 | borat | 700 | 1 | 11 | | 12 | 12 | borat | 700 | 1 | 12 | | 8 | 13 | borat | 700 | 1 | 13 | +------+------+--------+----------+-----------------+------------------------+ 4 rows in set (0.00 sec)
принятые ответы ' outout
SELECT tt.* FROM topten tt INNER JOIN ( SELECT home, MAX(datetime) AS MaxDateTime FROM topten GROUP BY home ) groupedtt ON tt.home = groupedtt.home AND tt.datetime = groupedtt.MaxDateTime +------+------+---------------------+--------+----------+ | id | home | datetime | player | resource | +------+------+---------------------+--------+----------+ | 1 | 10 | 2009-04-03 00:00:00 | john | 399 | | 2 | 11 | 2009-04-03 00:00:00 | juliet | 244 | | 5 | 12 | 2009-04-03 00:00:00 | borat | 555 | | 8 | 13 | 2009-01-01 00:00:00 | borat | 700 | | 9 | 10 | 2009-04-03 00:00:00 | borat | 700 | | 10 | 11 | 2009-04-03 00:00:00 | borat | 700 | | 12 | 12 | 2009-04-03 00:00:00 | borat | 700 | +------+------+---------------------+--------+----------+ 7 rows in set (0.00 sec)
другой способ gt самая последняя строка в группе с помощью подзапроса, который в основном вычисляет ранг для каждой строки в группе, а затем отфильтровывает ваши последние строки, как с rank = 1
select a.* from topten a where ( select count(*) from topten b where a.home = b.home and a.`datetime` < b.`datetime` ) +1 = 1
здесь визуальные демо для ранга нет для каждой строки для лучшего понимания
читая некоторые комментарии что делать, если есть две строки, которые имеют одинаковое поле "home" и " datetime ценности?
выше запрос не будет выполнен и вернет более 1 строк для выше ситуации. Чтобы скрыть эту ситуацию, потребуется другой критерий / параметр / столбец, чтобы решить, какую строку следует принять, которая попадает в вышеуказанную ситуацию. При просмотре образца набора данных я предполагаю, что есть столбец первичного ключа
id
который должен быть установлен на автоматическое увеличение. Таким образом, мы можем использовать этот столбец, чтобы выбрать самую последнюю строку, настроив тот же запрос с помощьюCASE
заявление типаselect a.* from topten a where ( select count(*) from topten b where a.home = b.home and case when a.`datetime` = b.`datetime` then a.id < b.id else a.`datetime` < b.`datetime` end ) + 1 = 1
выше запрос будет выбрать строку с самым высоким идентификатором среди тех же
datetime
значениявизуальные демо для ранга нет для каждой строки
попробуй такое
select * from mytable a join (select home, max(datetime) datetime from mytable group by home) b on a.home = b.home and a.datetime = b.datetime
С уважением К
Почему бы не использовать: Выберите home, MAX (datetime) в качестве MaxDateTime, player, resource из группы topten по home Я что-то пропустил?
это запрос, который вам нужен:
SELECT b.id, a.home,b.[datetime],b.player,a.resource FROM (SELECT home,MAX(resource) AS resource FROM tbl_1 GROUP BY home) AS a LEFT JOIN (SELECT id,home,[datetime],player,resource FROM tbl_1) AS b ON a.resource = b.resource WHERE a.home =b.home;
@Michae принятый ответ будет работать нормально в большинстве случаев, но он не подходит для одного, как показано ниже.
в случае, если было 2 строки, имеющие HomeID и Datetime же запрос будет возвращать обе строки, а не различные HomeID, как требуется, для этого добавить различные в запросе, как показано ниже.
SELECT DISTINCT tt.home , tt.MaxDateTime FROM topten tt INNER JOIN (SELECT home, MAX(datetime) AS MaxDateTime FROM topten GROUP BY home) groupedtt ON tt.home = groupedtt.home AND tt.datetime = groupedtt.MaxDateTime