如何在MySQL中选择每个组的第一行?
在 C# 中,它会是这样的:
table
.GroupBy(row => row.SomeColumn)
.Select(group => group
.OrderBy(row => row.AnotherColumn)
.First()
)
Linq-To-Sql 将其转换为以下 T-SQL 代码:
SELECT [t3].[AnotherColumn], [t3].[SomeColumn]
FROM (
SELECT [t0].[SomeColumn]
FROM [Table] AS [t0]
GROUP BY [t0].[SomeColumn]
) AS [t1]
OUTER APPLY (
SELECT TOP (1) [t2].[AnotherColumn], [t2].[SomeColumn]
FROM [Table] AS [t2]
WHERE (([t1].[SomeColumn] IS NULL) AND ([t2].[SomeColumn] IS NULL))
OR (([t1].[SomeColumn] IS NOT NULL) AND ([t2].[SomeColumn] IS NOT NULL)
AND ([t1].[SomeColumn] = [t2].[SomeColumn]))
ORDER BY [t2].[AnotherColumn]
) AS [t3]
ORDER BY [t3].[AnotherColumn]
但它与 MySQL 不兼容。
In C# it would be like this:
table
.GroupBy(row => row.SomeColumn)
.Select(group => group
.OrderBy(row => row.AnotherColumn)
.First()
)
Linq-To-Sql translates it to the following T-SQL code:
SELECT [t3].[AnotherColumn], [t3].[SomeColumn]
FROM (
SELECT [t0].[SomeColumn]
FROM [Table] AS [t0]
GROUP BY [t0].[SomeColumn]
) AS [t1]
OUTER APPLY (
SELECT TOP (1) [t2].[AnotherColumn], [t2].[SomeColumn]
FROM [Table] AS [t2]
WHERE (([t1].[SomeColumn] IS NULL) AND ([t2].[SomeColumn] IS NULL))
OR (([t1].[SomeColumn] IS NOT NULL) AND ([t2].[SomeColumn] IS NOT NULL)
AND ([t1].[SomeColumn] = [t2].[SomeColumn]))
ORDER BY [t2].[AnotherColumn]
) AS [t3]
ORDER BY [t3].[AnotherColumn]
But it is incompatible with MySQL.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
我的答案仅基于您帖子的标题,因为我不懂 C#,也不理解给定的查询。但在 MySQL 中我建议你尝试子选择。首先获取一组感兴趣的列的主键,然后从这些行中选择数据:
I based my answer on the title of your post only, as I don't know C# and didn't understand the given query. But in MySQL I suggest you try subselects. First get a set of primary keys of interesting columns then select data from those rows:
您可以尝试另一种方法,该方法不需要 ID 字段。
我仍然同意lfagundes的观点,即您应该添加一些主键..
还要注意,通过这样做,您无法(轻松)获得其他值与生成的some_colum,another_column对在同一行!你需要 lfagundes apprach 和 PK 才能做到这一点!
Here's another way you could try, that doesn't need that ID field.
Still I agree with lfagundes that you should add some primary key ..
Also beware that by doing this, you cannot (easily) get at the other values is the same row as the resulting some_colum, another_column pair! You'd need lfagundes apprach and a PK to do that!
当我写的时候
它有效。 IIRC 在其他 RDBMS 中这样的语句是不可能的,因为不属于分组键的列在没有任何聚合的情况下被引用。
这个“怪癖”的行为非常接近我想要的。所以我用它来得到我想要的结果:
When I write
It works. IIRC in other RDBMS such statement is impossible, because a column that doesn't belongs to the grouping key is being referenced without any sort of aggregation.
This "quirk" behaves very closely to what I want. So I used it to get the result I wanted:
最佳性能且易于使用:
Best performance and easy to use:
使用 MySQL v8+,您可以使用窗口函数
With MySQL v8+ you could use window functions
我建议使用MySql官方的这种方式:
通过这种方式,我们可以获得每篇文章的最高价格
I suggest to use this official way from MySql:
With this way, we can get the highest price on each article
您应该使用一些聚合函数来获取所需的 AnotherColumn 的值。也就是说,如果您想要 SomeColumn 的每个值(按数字或按字典顺序)的 AnotherColumn 的最低值,您可以使用:
一些希望有用的链接:
http://dev.mysql.com/doc/refman/5.1/en/group-by-functions.html
http://www.oreillynet.com/databases/blog/2007/05/debunking_group_by_myths .html
You should use some aggregate function to get the value of AnotherColumn that you want. That is, if you want the lowest value of AnotherColumn for each value of SomeColumn (either numerically or lexicographically), you can use:
Some hopefully helpful links:
http://dev.mysql.com/doc/refman/5.1/en/group-by-functions.html
http://www.oreillynet.com/databases/blog/2007/05/debunking_group_by_myths.html
来自 MySQL 5.7 文档
这意味着 @Jader Dias 的解决方案并不适用于所有地方。
以下是启用
ONLY_FULL_GROUP_BY
时有效的解决方案:From MySQL 5.7 documentation
This means that @Jader Dias's solution wouldn't work everywhere.
Here is a solution that would work when
ONLY_FULL_GROUP_BY
is enabled:rtribaldos 提到,在较新的数据库版本中,可以使用窗口函数。
这是一个对我有用的代码,并且与 Martin Zwarík 的 substring_index 解决方案(在 Mariadb 10.5.16 中)一样快:
rtribaldos mentioned that in younger database versions, window-functions could be used.
Here is a code which worked for me and was as fast as Martin Zwarík's substring_index-solution (in Mariadb 10.5.16):
我在答案中没有看到以下解决方案,所以我想我应该把它放在那里。
问题是在按
SomeColumn
分组的所有组中选择按AnotherColumn
排序时的第一行。以下解决方案将在 MySQL 中执行此操作。
id
必须是唯一的列,不得包含包含-
(我用作分隔符)的值。有一个针对
FIRST()
的功能请求,并且MySQL bug 跟踪器中的LAST()
,但它在很多年前就被关闭了。I have not seen the following solution among the answers, so I thought I'd put it out there.
The problem is to select rows which are the first rows when ordered by
AnotherColumn
in all groups grouped bySomeColumn
.The following solution will do this in MySQL.
id
has to be a unique column which must not hold values containing-
(which I use as a separator).There is a feature request for
FIRST()
andLAST()
in the MySQL bug tracker, but it was closed many years back.这个怎么样:
How about this:
另一种方法是
从在视图中工作的组中选择 max
Yet another way to do it
Select max from group that works in views
另一种方法(没有主键)是使用 JSON 函数:
或 pre 5.7.22
排序(或过滤)可以在分组之前完成:
...或在分组之后(当然):
不可否认,这相当令人费解,性能可能不是很好(没有在大数据上测试它,在我有限的数据集上运行良好)。
Yet another way to do it (without the primary key) would be using the JSON functions:
or pre 5.7.22
Ordering (or filtering) can be done before grouping:
... or after grouping (of course):
Admittedly, it's rather convoluted and performance is probably not great (didn't test it on large data, works well on my limited data sets).
我最近发现了一个很酷的技巧来实现这一点。基本上只是从表中创建两个不同的子查询并将它们连接在一起。其中一个子查询基于分组进行聚合,另一个子查询仅获取每个分组项的第一个 DISTINCT 行。
当您将这些子查询连接在一起时,您将获得每个组中的第一个不同的项目,但还将获得整个组中每个项目的聚合列。这与关闭 ONLY_FULL_GROUP_BY 的结果本质上相同。
I recently discovered a cool trick to accomplish this. Basically just make two different subqueries from a table and join them together. One of the subqueries does the aggregation based on a grouping, and the other subquery just grabs the first DISTINCT row for each grouped item.
When you join these subqueries together, you will get the first distinct item from each group, but will also get the aggregated columns across the whole group for each item. This is essentially the same result as having ONLY_FULL_GROUP_BY turned off.
在 Mysql 中选择每个组的第一行(按列排序)。
我们有:
一个表:mytable
我们排序的列:the_column_to_order_by
我们希望分组的列:the_group_by_column
这是我的解决方案。
内部查询为您提供一组唯一的行,选择作为双键。
外部查询通过连接这两个键(使用 AND)来连接同一个表。
仅供参考:我根本没有考虑过这方面的效率,也无法以某种方式谈论这一点。
Select the first row for each group (as ordered by a column) in Mysql .
We have:
a table: mytable
a column we are ordering by: the_column_to_order_by
a column that we wish to group by: the_group_by_column
Here's my solution.
The inner query gets you a unique set of rows, selected as a dual key.
The outer query joins the same table by joining on both of those keys (with AND).
FYI: I haven't thought about efficiency at all for this and can't speak to that one way or the other.
为什么不使用 MySQL LIMIT 关键字?
Why not use MySQL LIMIT keyword?