[英]How to select the first row for each group in 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 不兼容。
我的回答僅基於您帖子的標題,因為我不懂 C# 並且不理解給定的查詢。 但是在 MySQL 中,我建議您嘗試子選擇。 首先獲取一組有趣列的主鍵,然后從這些行中選擇數據:
SELECT somecolumn, anothercolumn
FROM sometable
WHERE id IN (
SELECT min(id)
FROM sometable
GROUP BY somecolumn
);
當我寫
SELECT AnotherColumn
FROM Table
GROUP BY SomeColumn
;
有用。 IIRC 在其他 RDBMS 中這樣的語句是不可能的,因為不屬於分組鍵的列在沒有任何類型的聚合的情況下被引用。
這種“怪癖”與我想要的非常接近。 所以我用它來得到我想要的結果:
SELECT * FROM
(
SELECT * FROM `table`
ORDER BY AnotherColumn
) t1
GROUP BY SomeColumn
;
這是您可以嘗試的另一種方法,不需要該 ID 字段。
select some_column, min(another_column)
from i_have_a_table
group by some_column
我仍然同意 lfagundes 您應該添加一些主鍵..
還要注意,通過這樣做,您不能(輕松)獲得其他值與結果 some_colum, another_column 對相同的行! 你需要 lfagundes apprach 和 PK 來做到這一點!
SELECT
t1.*
FROM
table_name AS t1
LEFT JOIN table_name AS t2 ON (
t2.group_by_column = t1.group_by_column
-- group_by_column is the column you would use in the GROUP BY statement
AND
t2.order_by_column < t1.order_by_column
-- order_by_column is column you would use in the ORDER BY statement
-- usually is the autoincremented key column
)
WHERE
t2.group_by_column IS NULL;
使用 MySQL v8+,您可以使用窗口函數
您應該使用一些聚合函數來獲取您想要的 AnotherColumn 的值。 也就是說,如果您想要 SomeColumn 的每個值(數字或字典順序)的 AnotherColumn 的最低值,您可以使用:
SELECT SomeColumn, MIN(AnotherColumn)
FROM YourTable
GROUP BY SomeColumn
一些希望有用的鏈接:
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.5 及更高版本實現了功能依賴檢測。 如果啟用了 ONLY_FULL_GROUP_BY SQL 模式(默認情況下是這樣),MySQL 將拒絕選擇列表、HAVING 條件或 ORDER BY 列表引用非聚合列的查詢,這些列既不在 GROUP BY 子句中命名,也不在功能上依賴它們.
這意味着@Jader Dias 的解決方案不會在任何地方都有效。
這是啟用ONLY_FULL_GROUP_BY
時ONLY_FULL_GROUP_BY
的解決方案:
SET @row := NULL;
SELECT
SomeColumn,
AnotherColumn
FROM (
SELECT
CASE @id <=> SomeColumn AND @row IS NOT NULL
WHEN TRUE THEN @row := @row+1
ELSE @row := 0
END AS rownum,
@id := SomeColumn AS SomeColumn,
AnotherColumn
FROM
SomeTable
ORDER BY
SomeColumn, -AnotherColumn DESC
) _values
WHERE rownum = 0
ORDER BY SomeColumn;
我在答案中沒有看到以下解決方案,所以我想我會把它放在那里。
問題是在按AnotherColumn
分組的所有組中按SomeColumn
排序時選擇第一行。
以下解決方案將在 MySQL 中執行此操作。 id
必須是一個唯一的列,它不能包含包含-
(我用作分隔符)的值。
select t1.*
from mytable t1
inner join (
select SUBSTRING_INDEX(
GROUP_CONCAT(t3.id ORDER BY t3.AnotherColumn DESC SEPARATOR '-'),
'-',
1
) as id
from mytable t3
group by t3.SomeColumn
) t2 on t2.id = t1.id
-- Where
SUBSTRING_INDEX(GROUP_CONCAT(id order by AnotherColumn desc separator '-'), '-', 1)
-- can be seen as:
FIRST(id order by AnotherColumn desc)
-- For completeness sake:
SUBSTRING_INDEX(GROUP_CONCAT(id order by AnotherColumn desc separator '-'), '-', -1)
-- would then be seen as:
LAST(id order by AnotherColumn desc)
在 MySQL 錯誤跟蹤器中有一個對FIRST()
和LAST()
的功能請求,但它在很多年前就被關閉了。
最佳性能且易於使用:
SELECT id, code,
SUBSTRING_INDEX( GROUP_CONCAT(price ORDER BY id DESC), ',', 1) first_found_price
FROM stocks
GROUP BY code
ORDER BY id DESC
我建議使用 MySql 中的這種官方方式:
SELECT article, dealer, price
FROM shop s1
WHERE price=(SELECT MAX(s2.price)
FROM shop s2
WHERE s1.article = s2.article
GROUP BY s2.article)
ORDER BY article;
通過這種方式,我們可以獲得每篇文章的最高價格
這個怎么樣:
SELECT SUBSTRING_INDEX(
MIN(CONCAT(OrderColumn, '|', IFNULL(TargetColumn, ''))
), '|', -1) as TargetColumn
FROM table
GROUP BY GroupColumn
另一種方法(沒有主鍵)是使用 JSON 函數:
select somecolumn, json_unquote( json_extract(json_arrayagg(othercolumn), "$[0]") )
from sometable group by somecolumn
或 5.7.22 之前的版本
select somecolumn,
json_unquote(
json_extract(
concat('["', group_concat(othercolumn separator '","') ,'"]')
,"$[0]" )
)
from sometable group by somecolumn
排序(或過濾)可以在分組之前完成:
select somecolumn, json_unquote( json_extract(json_arrayagg(othercolumn), "$[0]") )
from (select * from sometable order by othercolumn) as t group by somecolumn
...或分組后(當然):
select somecolumn, json_unquote( json_extract(json_arrayagg(othercolumn), "$[0]") ) as other
from sometable group by somecolumn order by other
不可否認,它相當復雜,性能可能不是很好(沒有在大數據上測試它,在我有限的數據集上運行良好)。
另一種方法來做到這一點
從在視圖中工作的組中選擇最大值
SELECT * FROM action a
WHERE NOT EXISTS (
SELECT 1 FROM action a2
WHERE a2.user_id = a.user_id
AND a2.action_date > a.action_date
AND a2.action_type = a.action_type
)
AND a.action_type = "CF"
在 Mysql 中為每個組選擇第一行(按列排序) 。
我們有:
一張桌子: mytable
我們排序的列: the_column_to_order_by
我們希望分組的列: the_group_by_column
這是我的解決方案。 內部查詢為您提供一組唯一的行,選擇為雙鍵。 外部查詢通過連接這兩個鍵(使用 AND)來連接同一個表。
SELECT * FROM
(
SELECT the_group_by_column, MAX(the_column_to_order_by) the_column_to_order_by
FROM mytable
GROUP BY the_group_by_column
ORDER BY MAX(the_column_to_order_by) DESC
) as mytable1
JOIN mytable mytable2 ON mytable2.the_group_by_column =
mytablealiamytable2.the_group_by_column
AND mytable2.the_column_to_order_by = mytable1.the_column_to_order_by;
僅供參考:我根本沒有考慮過效率問題,也無法以一種或另一種方式談論它。
我最近發現了一個很酷的技巧來實現這一點。 基本上只是從一個表中創建兩個不同的子查詢並將它們連接在一起。 其中一個子查詢基於分組進行聚合,另一個子查詢僅獲取每個分組項的第一個 DISTINCT 行。
當您將這些子查詢連接在一起時,您將從每個組中獲得第一個不同的項目,但也會為每個項目獲得整個組中的聚合列。 這與關閉 ONLY_FULL_GROUP_BY 的結果基本相同。
SELECT non_aggregated_data.foo_column AS foo_column,
non_aggregated_data.bar_column AS bar_column,
aggregated_data.value_1_sum AS value_1_sum,
aggregated_data.value_2_sum AS value_2_sum
FROM (SELECT column_to_self_join_on,
sum(value_1) AS value_1_sum,
sum(value_2) AS value_2_sum
FROM example_table
GROUP BY column_to_self_join_on) AS aggregated_data
LEFT JOIN (SELECT DISTINCT(column_to_self_join_on),
foo_column,
bar_column
FROM example_table) AS non_aggregated_data
ON non_aggregated_data.column_to_self_join_on = aggregated_data.column_to_self_join_on
rtribaldos 提到在較年輕的數據庫版本中,可以使用窗口函數。
這是一個對我有用的代碼,它與 Martin Zwarík 的substring_index解決方案一樣快(在 Mariadb 10.5.16 中):
SELECT * FROM (
SELECT group_col, order_col
, ROW_NUMBER() OVER(PARTITION BY group_col ORDER BY order_col) rnr
FROM some_table
WHERE <some_condition>
ORDER BY group_col
) i
WHERE rnr=1;
為什么不使用 MySQL LIMIT 關鍵字?
SELECT [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]
LIMIT 1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.