2012-10-17 18 views
16

Eventuali duplicati:
How to get the record of a table who contains the maximum value?SQL select max (data) e il valore corrispondente

Ho una query di aggregazione come la seguente:

SELECT TrainingID, Max(CompletedDate) as CompletedDate, Max(Notes) as Notes  --This will only return the longest notes entry 
FROM HR_EmployeeTrainings ET 
WHERE (ET.AvantiRecID IS NULL OR ET.AvantiRecID = @avantiRecID) 
GROUP BY AvantiRecID, TrainingID    

Quale è funziona e restituisce i dati corretti la maggior parte del tempo, ma ho notato un problema. Il campo Note che viene restituito non corrisponde necessariamente al record da cui proviene il massimo (completedDate). Invece sarà quello con la corda più lunga? O quello con il più alto valore ASCII? Cosa fa SQL Server in caso di parità tra due record? Non sono nemmeno sicuro. Quello che voglio ottenere è il campo delle note dal record max (completedDate). Come dovrei avere a fare questo?

+0

È completato Data non un DateTime? – Frobzig

+0

È un DateTime. Nessun problema con quel campo, ma con Notes. – MAW74656

+0

le note massime o ogni nota per il 'max (completedDate)'? – Marc

risposta

23

È possibile utilizzare una sottoquery. La sottoquery riceverà lo Max(CompletedDate). È poi prendere questo valore e di unirsi a vostro tavolo ancora una volta per recuperare la collegata nota con quella data:

select ET1.TrainingID, 
    ET1.CompletedDate, 
    ET1.Notes 
from HR_EmployeeTrainings ET1 
inner join 
(
    select Max(CompletedDate) CompletedDate, TrainingID 
    from HR_EmployeeTrainings 
    --where AvantiRecID IS NULL OR AvantiRecID = @avantiRecID 
    group by TrainingID 
) ET2 
    on ET1.TrainingID = ET2.TrainingID 
    and ET1.CompletedDate = ET2.CompletedDate 
where ET1.AvantiRecID IS NULL OR ET1.AvantiRecID = @avantiRecID 
3

Non c'è un modo semplice per farlo, ma qualcosa di simile questo funzionerà:

SELECT ET.TrainingID, 
    ET.CompletedDate, 
    ET.Notes 
FROM 
HR_EmployeeTrainings ET 
inner join 
(
    select TrainingID, Max(CompletedDate) as CompletedDate 
    FROM HR_EmployeeTrainings 
    WHERE (ET.AvantiRecID IS NULL OR ET.AvantiRecID = @avantiRecID) 
    GROUP BY AvantiRecID, TrainingID 
) ET2 
    on ET.TrainingID = ET2.TrainingID 
    and ET.CompletedDate = ET2.CompletedDate 
+0

la tua sintassi è errata per la tua sottoquery, ti manca una clausola 'FROM'. – Taryn

3

Ogni funzione MAX viene valutato singolarmente. Quindi MAX (CompletedDate) restituirà il valore dell'ultima colonna CompletedDate e MAX (Notes) restituirà il valore massimo (cioè più alto alfabeticamente).

È necessario strutturare la query in modo diverso per ottenere ciò che si desidera. Questa questione era in realtà già stato chiesto e ha risposto più volte, quindi non mi ripeto:

How to find the record in a table that contains the maximum value?

Finding the record with maximum value in SQL

+1

Se la domanda è stata risolta molte volte prima, la cosa giusta da fare è votare per chiudere come "duplicato esatto" – Tony

+0

Thx, l'ho fatto ora. – Marplesoft

5

Ah, sì, è così che è destinato in SQL. Ottieni il massimo di ogni colonna separatamente. Sembra che tu voglia restituire i valori dalla riga con la data massima, quindi devi selezionare la riga con la data massima. Preferisco farlo con una sottoselezione, poiché le query mantengono compatto facile da leggere.

SELECT TrainingID, CompletedDate, Notes 
FROM HR_EmployeeTrainings ET 
WHERE (ET.AvantiRecID IS NULL OR ET.AvantiRecID = @avantiRecID) 
AND CompletedDate in 
    (Select Max(CompletedDate) from HR_EmployeeTrainings B 
    where B.TrainingID = ET.TrainingID) 

Se anche voi volete abbinare con AntiRecID si dovrebbe includere che nella selezione secondaria pure.