2010-04-29 43 views
43

En C# sería así:¿Cómo seleccionar la primera fila para cada grupo en MySQL?

table 
    .GroupBy(row => row.SomeColumn) 
    .Select(group => group 
     .OrderBy(row => row.AnotherColumn) 
     .First() 
    ) 

LINQ to SQL lo traduce al siguiente código de 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] 

Pero es incompatible con MySQL.

+0

que no se puede controlar el servidor de base de datos para ver qué consultas de C# se ejecuta (que soy una-lo que adivinar que su sintaxis anterior es LINQ) – lexu

+0

@Iexu Sí puedo, y lo hice con MS SQL Server. Pero no tengo ningún Linq-to-MySQL, solo Linq-To-Sql –

Respuesta

17

Cuando escribo

SELECT AnotherColumn 
FROM Table 
GROUP BY SomeColumn 
; 

Funciona. IIRC en otro RDBMS tal declaración es imposible, porque se hace referencia a una columna que no pertenece a la clave de agrupación sin ningún tipo de agregación.

Esta "peculiaridad" se comporta muy de cerca a lo que quiero. Así que he usado para obtener el resultado que quería:

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

En un caso similar, la parte de selección funciona para mí, pero cuando intento hacer una actualización del resultado obtenido con esta consulta en mysql, no funciona. He intentado muchas soluciones hasta ahora para "actualizar" sin éxito. Agradecería cualquier ayuda/sugerencia allí. – user3445140

+3

Discusión acerca de por qué funciona la primera declaración: http://stackoverflow.com/questions/1225144/why-does-mysql-allow-group-by-queries-without-aggregate-functions. Al parecer, al iniciar MySQL 5.7.5 esto será deshabilitado de forma predeterminada, http://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_only_full_group_by –

60

Basé mi respuesta solo en el título de su publicación, ya que no sé C# y no entendí la consulta dada. Pero en MySQL te sugiero que intentes subselects. En primer lugar obtener un conjunto de claves primarias de columnas interesantes a continuación, seleccione los datos de las filas:

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

Creo que funcionará para mí, pero esta solución requiere que cree un 'id' de PK para mi tabla. –

+0

Si bien la solución C#/T-SQL no lo requiere. –

+6

Bueno, es una buena práctica tener siempre una clave principal y, teóricamente, si no tiene una clave primaria, el conjunto de la fila completa debería ser su clave principal (aunque MySQL aceptaría una tabla sin clave principal con filas repetidas)) – lfagundes

5

Se debe utilizar una función de agregado para obtener el valor de AnotherColumn que desea. Es decir, si desea que el valor más bajo de AnotherColumn para cada valor de SomeColumn (numéricamente o lexicográfico), puede utilizar:

SELECT SomeColumn, MIN(AnotherColumn) 
FROM YourTable 
GROUP BY SomeColumn 

Algunos enlaces con suerte votos:

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

Cuando hago eso, el valor SomeColumn no es necesariamente el valor en la fila donde AnotherColumn = Min (AnotherColumn) –

+0

@Jader Dias: Como dije en mi respuesta, ¡por eso necesitarías un PK! – lexu

+1

Min (AnotherColumn) en el contexto de agrupamiento es el AnotherColumn más bajo para el grupo de filas con el mismo valor de SomeColumn, no para todos los valores de AnotherColumn para toda la tabla. –

12

Aquí hay otra forma de probar, que no necesita ese campo ID.

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

Todavía estoy de acuerdo con lfagundes que se debe agregar una cierta clave primaria ..

También tenga cuidado de que al hacer esto, no se puede (fácilmente) llegar a los demás valores es la misma fila que el some_colum resultante , otro par de columna! ¡Necesitarías un apprat de lfagundes y un PK para hacerlo!

+0

¡esto tiene más sentido! – Kefka

+0

Esa es la solución perfecta para mí. – MeLight

0

Sin embargo, otra manera de hacerlo

SELECT MAX del grupo que trabaja en las vistas

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

Por qué no usar MySQL palabra clave límite?

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

Esto devuelve la primera fila de la * consulta completa *, no la primera fila de * cada grupo *. Debería * haber * una forma de hacer esto para cada grupo, dada la frecuencia de esta pregunta, pero los grupos de SQL estaban demasiado ocupados discutiendo sobre el significado de NULL para molestarse con problemas prácticos como este. –

0

¿Qué tal esto:

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

De MySQL 5.7 documentation

MySQL 5.7.5 y hasta instrumentos de detección de dependencia funcional.Si el modo SQL ONLY_FULL_GROUP_BY está habilitado (que es por defecto), MySQL rechaza consultas para las cuales la lista de selección, la condición HAVING o la lista ORDER BY se refieren a columnas no agregadas que no están nombradas en la cláusula GROUP BY ni son funcionalmente dependientes de ellas .

Esto significa que la solución de @Jader Dias no funcionaría en todas partes.

Aquí es una solución que funciona cuando está habilitado 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; 
Cuestiones relacionadas