2012-02-20 16 views
5

que he visto algunas soluciones bastante en este tipo de problemas, pero ninguno de ellos parecen ser apropiadas:seleccionar filas con Max Valor agrupadas por dos columnas

tengo la siguiente tabla diseño, un control de versiones de los archivos adjuntos, que están unidos a las entidades:

TABLE attachments 
+------+--------------+----------+----------------+---------------+ 
| id | entitiy_id | group_id | version_number | filename  | 
+------+--------------+----------+----------------+---------------+ 
| 1 | 1   | 1  | 1    | file1-1.pdf | 
| 2 | 1   | 1  | 2    | file1-2.pdf | 
| 3 | 1   | 2  | 1    | file2-1.pdf | 
| 4 | 2   | 1  | 1    | file1-1.pdf | 
| 5 | 2   | 1  | 2    | file1-2.pdf | 
| 6 | 2   | 3  | 1    | file3-1.pdf | 
+------+--------------+----------+----------------+---------------+ 

salida debe ser el número máximo de versiones, agrupados por group_id y entity_id, yo solamente necesito una lista de entity_ids individuales si eso ayuda:

+------+--------------+----------+----------------+---------------+ 
| id | entitiy_id | group_id | version_number | filename  | 
+------+--------------+----------+----------------+---------------+ 
| 2 | 1   | 1  | 2    | file1-2.pdf | 
| 3 | 1   | 2  | 1    | file2-1.pdf | 
| 5 | 2   | 1  | 2    | file1-2.pdf | 
| 6 | 2   | 3  | 1    | file3-1.pdf | 
+------+--------------+----------+----------------+---------------+ 

Lo que he llegado con este auto es unirse a uno:

SELECT * 
FROM `attachments` `attachments` 
     LEFT OUTER JOIN attachments t2 
     ON (attachments.group_id = t2.group_id 
       AND attachments.version_number < t2.version_number) 
WHERE (t2.group_id IS NULL) 
    AND (`t2`.`id` = 1) 
GROUP BY t2.group_id 

Pero ésta sólo funciona si las diferentes entidades no comparten mismos números de grupo. Esto, desafortunadamente es necesario.

Encontré una solución de trabajo al crear una vista, pero esto no es compatible con mi configuración actual.

Todas las ideas son muy apreciadas. ¡Gracias!

Respuesta

3

Prueba esto:

select t1.* from attachments t1 
left join attachments t2 
on t1.entity_id = t2.entity_id and t1.group_id = t2.group_id and 
    t1.version_number < t2.version_number 
where t2.version_number is null 
+0

Gracias! Esta es una solución muy simple. –

+0

Al menos me aseguraría de agregar la clave que sugerí para mantener el rendimiento de la tabla, por lo entitiy_id, group_id y version_number. En su pregunta, usted especificó que era para identificación de entidad única, y esta opción funcionará más lentamente que las otras sugerencias en volúmenes de tabla superiores debido a que entity_id no se usa para limitar la unión. –

+0

-1 para no ANSI –

2

Esto funcionaría para la selección de todos los

SELECT attachments.* 
FROM (
    SELECT entitiy_id, group_id, MAX(version_number) AS max_version 
    FROM attachments 
    GROUP BY entitiy_id, group_id 
) AS maxVersions 
INNER JOIN attachments 
ON attachments.entitiy_id = maxVersions.entitiy_id 
AND attachments.group_id = maxVersions.group_id 
AND attachments.version_number = maxVersions.max_version 

Ampliando esto sólo tiene que buscar una sola entitiy_id implicaría simplemente añadiendo una DONDE en la sub consulta, por lo que esto daría

SELECT attachments.* 
FROM (
    SELECT entitiy_id, group_id, MAX(version_number) AS max_version 
    FROM attachments 
    WHERE entitity_id = [[YOUR ENTITIY ID HERE]] 
    GROUP BY entitiy_id, group_id 
) AS maxVersions 
INNER JOIN attachments 
ON attachments.entitiy_id = maxVersions.entitiy_id 
AND attachments.group_id = maxVersions.group_id 
AND attachments.version_number = maxVersions.max_version 

Si desea para asegurarse de que esto continúe operando rápidamente a medida que aumenta el número de filas, le aconsejo que se asegure de agregar una clave en los archivos adjuntos con las filas (entitiy_id, group_id, max_version), ya que la subconsulta podría contar con eso para asegurarse de que no se bloquea. arriba de la mesa

2

Esto haría el truco:

select a1.* from attachments a1 
inner join (select entitiy_id, group_id, max(version_number) as version_number 
      from attachments 
      group by entitiy_id, group_id) a2 on a1.entitiy_id = a2.entitiy_id and 
                a1.group_id = a2.group_id and 
                a1.version_number = a2.version_number 
0

También puede resolver este utilizando una expresión de tabla común de alto rendimiento (CTE).

WITH CTE AS 
(
SELECT entitiy_id, group_id, version_number, filename,  
ROW_NUMBER() OVER (PARTITION BY entitiy_id, group_id ORDER BY version_number DESC) as RowNum 
FROM attachments 
) 
SELECT entitiy_id, group_id, version_number, filename 
FROM CTE 
WHERE RowNum = 1 

O

SELECT T.entitiy_id, T.group_id, T.version_number, T.filename 
FROM (SELECT entitiy_id, group_id, version_number, filename,  
    ROW_NUMBER() OVER (PARTITION BY entitiy_id, group_id ORDER BY version_number DESC) as RowNum 
    FROM attachments 
    ) as T 
WHERE RowNum = 1 
Cuestiones relacionadas