Mysql SQL仅选择列上具有最大值的行
我有此文件表(此处为简化版): 身份证件 修订版 内容 1. 1. ... 2. 1. ... 1. 2. ... 1. 3. ... 乍一看。。。 您只需要一个带有Mysql SQL仅选择列上具有最大值的行,mysql,sql,aggregate-functions,greatest-n-per-group,groupwise-maximum,Mysql,Sql,Aggregate Functions,Greatest N Per Group,Groupwise Maximum,我有此文件表(此处为简化版): 身份证件 修订版 内容 1. 1. ... 2. 1. ... 1. 2. ... 1. 3. ... 乍一看。。。 您只需要一个带有MAXaggregate函数的groupby子句: SELECT id, MAX(rev) FROM YourTable GROUP BY id 事情从来没有这么简单,是吗? 我刚刚注意到您还需要内容列 在SQL中,这是一个非常常见的问题:根据某个组标识符在列中查找具有某个最大值的行的整个数据。在我的职业生涯中,我经常听到这样的话
MAX
aggregate函数的groupby
子句:
SELECT id, MAX(rev)
FROM YourTable
GROUP BY id
事情从来没有这么简单,是吗?
我刚刚注意到您还需要内容
列
在SQL中,这是一个非常常见的问题:根据某个组标识符在列中查找具有某个最大值的行的整个数据。在我的职业生涯中,我经常听到这样的话。事实上,这是我在当前工作的技术面试中回答的问题之一
实际上,StackOverflow社区创建了一个标记来处理这样的问题,这是非常普遍的
基本上,您有两种方法来解决该问题:
与简单的组标识符联接,组中的最大值
子查询
在这种方法中,首先在子查询中找到组标识符,即组中的最大值
(上面已经解决)。然后将表加入子查询,并在组标识符
和组中的最大值
上相等:
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
左与自连接,调整连接条件和过滤器
在这种方法中,您只需将表本身连接起来。在组标识符中出现相等。然后,两个聪明的动作:
第二个联接条件是左侧值小于右侧值
执行步骤1时,实际具有最大值的行的右侧将具有NULL
(这是一个左连接,记得吗?)。然后,我们过滤连接的结果,只显示右侧为NULL
的行
因此,你最终会:
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;
选择一个*
从你的桌子上
左表b
在a.id=b.id和a.rev
结论
这两种方法都带来了完全相同的结果
如果对于组标识符
,组中有两行的最大值
,则两种方法的结果中都有这两行
这两种方法都与SQL ANSI兼容,因此,无论其“风格”如何,都可以与您喜爱的RDBMS一起使用
这两种方法也都是性能友好的,但是您的里程可能会有所不同(RDBMS、DB结构、索引等)。因此,当您选择一种方法而不是另一种方法时,请选择基准。并确保选择对您最有意义的代码。我的偏好是使用尽可能少的代码
您可以在
试试这个:
SELECT *
FROM t1 WHERE (id,rev) IN
( SELECT id, MAX(rev)
FROM t1
GROUP BY id
)
在我看来,它不那么复杂。。。更容易阅读和维护。像这样的东西
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)
我不能保证它的性能,但这里有一个技巧,灵感来自微软Excel的局限性。它有一些好的特性 好东西
- 即使出现平局,它也应该强制只返回一条“最大记录”(有时有用)
- 它不需要连接
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
压缩首先强制rev列为一个已知字符长度的数字,而不考虑rev的值,例如
- 3.2变为1003.201
- 57变为1057.001
- 923.88变为1923.881
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
另一种解决方案是使用相关子查询:
select yt.id, yt.rev, yt.contents
from YourTable yt
where rev =
(select max(rev) from YourTable st where yt.id=st.id)
在(id,rev)上有一个索引会将子查询呈现为一个简单的查找
以下是与@AdrianCarneiro的答案(子查询,leftjoin)中的解决方案的比较,基于MySQL的测量,InnoDB表有约100万条记录,组大小为:1-3
对于完整表扫描,子查询/左连接/相关计时相互关联为6/8/9,而对于直接查找或批处理(id in(1,2,3)
),子查询比其他子查询慢得多(因为重新运行子查询)。然而,我无法在速度上区分leftjoin和相关解决方案
最后一个注意事项是,由于leftjoin在组中创建n*(n+1)/2个联接,其性能会受到组大小的严重影响…此解决方案仅从表中选择一个,因此速度更快。根据sqlfiddle.com上的测试,它只适用于MySQL和SQLite(用于SQLite remove DESC)。也许它可以调整到其他我不熟悉的语言上
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
不是mySQL,但是对于发现这个问题并使用SQL的其他人来说,另一种解决问题的方法是使用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
因为这是关于这个问题最流行的问题,我也会在这里重新发布另一个答案: 看起来有更简单的方法来实现这一点(但是仅在MySQL中实现): 请相信中的用户Bohemian的回答,因为它为这个问题提供了如此简洁优雅的答案 编辑:尽管此解决方案适用于许多p
select *
from (select * from mytable order by id, rev desc ) x
group by id
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
)
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
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)
select t.*
from test as t
join
(select max(rev) as rev
from test
group by id) as o
on o.rev = t.rev
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'
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;
select * from
(select * from table_name
order by id,rev desc) temp
group by id
SELECT * FROM (SELECT * FROM table1 ORDER BY id, rev DESC) X GROUP BY X.id;
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')
;
id rev content
1 2 One-Two
2 2 Two-Two
3 3 Three-Two
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
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;
id max(Table1.rev) max(Table2.content)
1 3 ..d
2 1 ..b
SELECT *
FROM
(SELECT *
FROM Employee
ORDER BY Salary DESC)
AS employeesub
GROUP BY employeesub.Salary;
SELECT *
FROM Employee
WHERE Employee.id = 12345
ORDER BY Employee.Salary DESC
LIMIT 1
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
with score as (select max(score_up) from history)
select history.* from score, history where history.score_up = score.max
SELECT *
FROM Employee
where Employee.Salary in (select max(salary) from Employee group by Employe_id)
ORDER BY Employee.Salary
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)
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
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
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
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
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;
select * from docs where (id, rev) IN (select id, max(rev) as rev from docs group by id order by id)
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()