2010-04-29 4 views
43

В C# это было бы так:Как выбрать первую строку для каждой группы в 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.

+0

вы не можете контролировать сервер БД, чтобы увидеть, что запросы C# Выполняет (я какой-то, догадываясь, что ваш синтаксис выше LINQ) – lexu

+0

@Iexu Да, я могу, и я сделал это с MS SQL Server. Но у меня нет Linq-to-MySQL, только Linq-To-Sql –

ответ

17

Когда я пишу

SELECT AnotherColumn 
FROM Table 
GROUP BY SomeColumn 
; 

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

Эта «причуда» ведет себя очень близко к тому, что я хочу. Таким образом, я использовал его, чтобы получить результат, я хотел:

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

В подобном случае часть выбора работает для меня, но когда я пытаюсь выполнить обновление результата, полученного с помощью этого запроса в mysql, это не сработает. До сих пор я пробовал много решений для «обновления» без каких-либо успехов. Был бы признателен за любую помощь/предложение. – user3445140

+3

Обсуждение вопроса о том, почему работает первое утверждение: http://stackoverflow.com/questions/1225144/why-does-mysql-allow-group-by-queries-without-aggregate-functions. Очевидно, начиная с MySQL 5.7.5 это будет отключено по умолчанию, http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by –

60

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

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

Я думаю, что это сработает для меня, но для этого решения требуется создать PK 'id' для моей таблицы. –

+0

Хотя решение C#/T-SQL этого не требует. –

+6

Ну, это хорошая практика всегда иметь первичный ключ, и теоретически, если у вас нет первичного ключа, набор цельной строки должен быть вашим основным ключом (хотя MySQL будет принимать таблицу без первичного ключа с повторяющимися строками). – lfagundes

5

Вы должны использовать некоторую агрегатную функцию, чтобы получить значение 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

+0

Когда я это делаю, значение SomeColumn не обязательно является значением в строке, где AnotherColumn = Min (AnotherColumn) –

+0

@Jader Dias: Как я сказал в своем ответе, вот почему вам нужен ПК! – lexu

+1

Min (AnotherColumn) в контексте группировки - это самый низкий AnotherColumn для группы строк с тем же значением SomeColumn, но не для всех значений AnotherColumn для всей таблицы. –

12

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

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

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

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

+0

это имеет смысл вообще! – Kefka

+0

Это идеальное решение для меня. – MeLight

0

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

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

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" 
-2

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

Это возвращает первую строку * всего запроса *, а не первую строку * каждой группы *. Там * должен * быть способом сделать это для каждой группы, учитывая, насколько распространен этот вопрос, но группы SQL были слишком заняты, рассуждая о значении NULL, чтобы беспокоиться о таких практических проблемах, как это. –

0

Как об этом:

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

От MySQL 5.7 documentation

MySQL 5.7.5 и выше орудий выявления функциональной зависимости.Если включен режим ONLY_FULL_GROUP_BY SQL (который он по умолчанию), MySQL отклоняет запросы, для которых список выбора, условие HAVING или список ORDER BY относятся к неагрегированным столбцам, которые не имеют ни имени в предложении GROUP BY, ни функционально зависят от них ,

Это означает, что решение @Jader Dias не будет работать повсюду.

Вот решение, которое будет работать, когда 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; 
Смежные вопросы