Как выбрать первую строку для каждой группы в MySQL?

В С# это будет так:

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.

Ответ 1

Когда я пишу

SELECT AnotherColumn
FROM Table
GROUP BY SomeColumn
;

Это работает. IIRC в другой СУБД такое утверждение невозможно, поскольку столбец, который не принадлежит ключу группировки, ссылается без какой-либо агрегации.

Эта "причуда" ведет себя очень близко к тому, что я хочу. Поэтому я использовал его для получения желаемого результата:

SELECT * FROM 
(
 SELECT * FROM `table`
 ORDER BY AnotherColumn
) t1
GROUP BY SomeColumn
;

Ответ 2

Я основывал свой ответ только на заголовке вашего сообщения, так как я не знаю С# и не понял данный запрос. Но в MySQL я предлагаю вам попробовать подзапросы. Сначала получите набор первичных ключей интересных столбцов, затем выберите данные из этих строк:

SELECT somecolumn, anothercolumn 
  FROM sometable 
 WHERE id IN (
               SELECT min(id) 
                 FROM sometable 
                GROUP BY somecolumn
             );

Ответ 3

Здесь вы можете попробовать другой способ, который не нуждается в этом поле ID.

select some_column, min(another_column)
  from i_have_a_table
 group by some_column

Я согласен с lfagundes, что вы должны добавить первичный ключ.

Также будьте осторожны, что, делая это, вы не можете (легко) получить другие значения - это та же строка, что и в результате пары some_colum, another_column! Вам понадобится оценка lfagundes и ПК, чтобы сделать это!

Ответ 4

Вы должны использовать некоторую функцию агрегата, чтобы получить значение AnotherColumn, которое вы хотите. То есть, если вы хотите получить меньшее значение AnotherColumn для каждого значения SomeColumn (либо численно, либо лексикографически), вы можете использовать:

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

Ответ 5

Еще один способ сделать это

Выберите max из группы, которая работает в представлениях

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"

Ответ 6

Как насчет этого:

SELECT SUBSTRING_INDEX(
      MIN(CONCAT(OrderColumn, '|', IFNULL(TargetColumn, ''))
    ), '|', -1) as TargetColumn
FROM table
GROUP BY GroupColumn

Ответ 7

Почему бы не использовать ключевое слово 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