我如何select与MAX(列值)的行,DISTINCT由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 

我需要select每个不同的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 

不。 给所有的logging。

 -- 3 ..something exotic: 

有不同的结果。

你太亲近了! 所有你需要做的就是selectBOTH home并且它是最大date时间,然后返回到BOTH字段的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 

这里是T-SQL版本:

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

编辑
不幸的是,MySQL中没有RANK()OVER函数。
但是它可以被模拟,请参阅使用MySQL模拟分析(AKA排名)函数 。
所以这是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解决scheme,没有内部查询,也没有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栏join表格。 使用LEFT JOIN确保表m中的所有行都出现在结果集中。 那些在表格b没有匹配的对于b的列将有NULL

JOIN上的另一个条件要求仅匹配来自bdatetime列上的值大于m行的行。

使用问题中发布的数据, LEFT JOIN将产生这对:

 +------------------------------------------+--------------------------------+ | the row from `m` | the matching row from `b` | |------------------------------------------|--------------------------------| | id home datetime player resource | id home datetime ... | |----|-----|------------|--------|---------|------|------|------------|-----| | 1 | 10 | 04/03/2009 | john | 399 | NULL | NULL | NULL | ... | * | 2 | 11 | 04/03/2009 | juliet | 244 | NULL | NULL | NULL | ... | * | 5 | 12 | 04/03/2009 | borat | 555 | NULL | NULL | NULL | ... | * | 3 | 10 | 03/03/2009 | john | 300 | 1 | 10 | 04/03/2009 | ... | | 4 | 11 | 03/03/2009 | juliet | 200 | 2 | 11 | 04/03/2009 | ... | | 6 | 12 | 03/03/2009 | borat | 500 | 5 | 12 | 04/03/2009 | ... | | 7 | 13 | 24/12/2008 | borat | 600 | 8 | 13 | 01/01/2009 | ... | | 8 | 13 | 01/01/2009 | borat | 700 | NULL | NULL | NULL | ... | * +------------------------------------------+--------------------------------+ 

最后, WHERE子句只保留b列中有NULL的对(在上面的表中用*标记); 这意味着,由于JOIN子句的第二个条件,从m中select的行在列datetime具有最大值。

阅读SQL反模式:避免其他SQL技巧的数据库编程的陷阱 。

即使你有两个或两个以上的行,每个home都有相同的DATETIME

 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 

但是如果您还需要其他栏目,只需join原始表格(查看Michael La Voie答案)

最好的祝福。

由于人们似乎不断遇到这个线程(评论date范围从1.5年)是不是这么简单:

SELECT * FROM (SELECT * FROM topten ORDER BY datetime DESC) tmp GROUP BY home

没有聚合function需要…

干杯。

你也可以试试这个,对于大型表格查询性能会更好。 它适用于每个家庭不超过两个logging,并且他们的date不同。 更好的一般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) 

尝试这个

 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 

问候K

这里是MySQL版本,它只打印一个条目,其中重复MAX(date时间)在一个组中。

你可以在这里testinghttp://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 | +------+------+---------------------+--------+----------+ 

带有用户variables的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) 

为什么不使用:SELECT home,MAX(datetime)AS MaxDateTime,player,resource FROM topten GROUP BY 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接受的答案在大多数情况下都能正常工作,但是对于下面的答案是失败的。

如果有两行HomeID和Datetime相同,则查询将返回两行,而不是按需要返回不同的HomeID,以便在查询中添加Distinct,如下所示。

 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 

另一种方法是使用一个子查询按照每个组计算最近一行,然后根据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 

DEMO

这里是为了更好地理解每行的视觉演示

通过阅读一些评论,如果有两行具有相同的“家”和“date时间”字段值?

以上查询将失败,并将返回超过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 

DEMO

上面的查询将select相同datetime值中具有最高id的行

视觉演示为每行排名no