How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
我的表是:
1 2 3 4 5 6 7 8 9 10 | 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 |
我需要选择每个不同的
结果是:
1 2 3 4 5 6 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
不起作用。结果集有130行,但数据库有187行。结果包括
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
不。提供所有记录。
1 | -- 3 ..something exotic: |
有各种各样的结果。
你太亲密了!您所需要做的只是同时选择主页及其最长日期时间,然后在这两个字段上重新连接到
1 2 3 4 5 6 7 8 |
下面是T-SQL版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | -- 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 ranking)函数。所以这是MySQL版本:
1 2 3 4 5 6 7 |
最快的
1 2 3 4 5 6 | 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 |
说明:
使用
使用问题中发布的数据,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | +------------------------------------------+--------------------------------+ | 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 | ... | * +------------------------------------------+--------------------------------+ |
最后,
阅读SQL反模式:避免数据库编程书中的陷阱以获取其他SQL提示。
即使每个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
我认为这会给你期望的结果:
但如果您还需要其他列,只需与原始表进行联接(检查
最好的问候。
因为人们似乎一直在关注这个话题(评论日期从1.5年开始),这就不简单了:
不需要聚合函数…
干杯。
您也可以尝试这个方法,对于大表,查询性能会更好。当每个家庭的记录不超过两个,并且日期不同时,它就会工作。更好的一般mysql查询是来自上面的michael la voie。
1 2 3 4 5 |
如果是Postgres或提供分析功能的DBS,请尝试
1 2 3 4 5 6 7 8 9 |
这适用于Oracle:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
请为SQL Server尝试此操作:
1 2 3 4 |
1 2 3 4 5 6 7 8 9 10 11 |
另一种方式到现在每行集团GT的最近使用的子query,basically calculates的秩为每行每集团,然后过滤出你现在最近rows AS与秩= 1 P / < >
1 2 3 4 5 6 7 8 |
演示 P / < >
这里的视觉演示为排名没有为每行为更好的理解 P / < >
By reading some comments what about if there are two rows which have same 'home' and 'datetime' field values?
在query将失败和回报将超过1 rows为上面的情况。到盖起来,这样的情况将有需要的另一个parameter /标准/柱过程中的决定,行应该采取的瀑布,在上面的情况。通过viewing的样本数据集)为此承担有主要的关键
1 2 3 4 5 6 7 8 9 10 11 12 |
演示 P / < >
在query将选择行与highest id among同样
视觉演示为排名没有为每一行 P / < >
1 2 3 |
这里是mysql版本,它只打印一个条目,其中一个组中有重复的max(datetime)。
你可以在这里测试http://www.sqlpiddle.com/!2/0A4AE/1
样本数据1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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) |
接受的答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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) |
为什么不使用:选择home,max(datetime)作为maxdatetime,player,resource from topten group by home我错过什么了吗?
试试这个
1 2 3 4 5 |
当做K
这是您需要的查询:
1 2 3 4 5 6 7 |
@在大多数情况下,被接受的答案都会很好地解决,但下面的一个答案却失败了。
如果有两行的homeID和datetime相同,那么查询将返回两行,而不是所需的不同homeID,如下所示。
1 2 3 4 5 6 7 8 |