2012-02-20 11 views
5

ho visto alcune soluzioni abbastanza su questo tipo di problema, ma nessuno di questi sembra essere appropriato:Selezionare le righe con Max Valore raggruppate per due colonne

ho la seguente tabella il layout, una delle versioni di allegati, che sono destinati a entità:

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 | 
+------+--------------+----------+----------------+---------------+ 

uscita dovrebbe essere Max numero di versione, raggruppati per group_id e ENTITY_ID, avevo solo bisogno di una lista per singoli entity_ids se questo aiuta:

+------+--------------+----------+----------------+---------------+ 
| 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 | 
+------+--------------+----------+----------------+---------------+ 

Quello che ho venire in mente è questa auto unire 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 

Ma questo funziona solo se entità diverse non condividono i numeri stesso gruppo. Questo, purtroppo, è necessario.

Mi sono imbattuto in una soluzione funzionante durante la creazione di una vista, ma questo non è supportato nella mia configurazione corrente.

Tutte le idee sono molto apprezzate. Grazie!

risposta

3

Prova questa:

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

Grazie! Questa è una soluzione molto semplice. –

+0

Vorrei almeno assicurarmi di aggiungere la chiave che ho suggerito per mantenere le prestazioni della tabella, quindi entitiy_id, group_id e version_number. Nella tua domanda hai specificato che era per ID entità singola, e questa opzione sarà più lenta rispetto agli altri suggerimenti a volumi di tabelle più elevati a causa di entity_id che non viene utilizzato per limitare il join. –

+0

-1 per non ANSI –

2

Questo potrebbe funzionare per la selezione di tutti i

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 

Espansione questo per guardare solo per un singolo entitiy_id sarebbe semplicemente comportare l'aggiunta di un WHERE nella subquery, quindi questo darebbe

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 

Se lo si desidera per assicurarti che continui a funzionare velocemente con l'aumento del numero di righe, ti consiglio di assicurarti di aggiungere una chiave sugli allegati con le righe (entitiy_id, group_id, max_version), in quanto la subquery sarebbe in grado di fare affidamento su ciò assicurando che non si blocchi sul tavolo.

2

Ciò farebbe il trucco:

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

È inoltre possibile risolvere questo problema utilizzando un rendimento elevato Common Table Expression (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 
Problemi correlati