2016-05-26 62 views
5

Ho due tabelle, un "master" è un elenco principale di nomi e il secondo "scenario" è un elenco di più scenari per ciascun nome dall'elenco principale . Voglio che la mia query INNER JOIN recuperi l'elenco principale di ID con lo stato della colonna dalla tabella "scenario" ma solo lo stato più recente basato su scenarioID. Ecco il codice che ho provato e tavoli con output desideratoSQL inner join su una colonna in base al valore massimo da un'altra colonna

SELECT DISTINCT a.[user], a.ID, a.Name, b.status 
from master a 
INNER JOIN scenario b ON a.ID = b.ID 
WHERE 
    b.scenarioID = (
      SELECT max(scenarioID) FROM scenario c2 WHERE c2.ID=c.ID) 

Maestro

ID user Name 
425 John Skyline 
426 John Violin 
427 Joe  Pura 

Scenario

ID ScenarioID status 
425 1    active 
425 2    active 
425 3    done 
426 1    active 
426 2    active 
427 1    done 

output desiderato

ID user Name status 
425 John Skyline done 
426 John Violin active 
427 Joe  Pura done 
+0

http://stackoverflow.com/questions/1313120/retrieving-the-last-record-in-each-group è per mysql server non SQL così ci sono diversi modi per risolvere il problema. Anche questa domanda implica l'adesione all'ultimo record mentre la domanda duplicata sta solo cercando di ottenere l'ultimo all'interno di un tavolo. –

risposta

1

Ecco una formulazione leggermente diversa che utilizza un CTE, che io in genere trovo più facile da leggere rispetto a una sottoquery (anche se, ovviamente, la vostra situazione potrebbe essere diversa).

declare @Master table 
(
    ID bigint, 
    [user] varchar(16), 
    Name varchar(16) 
); 

declare @Scenario table 
(
    ID bigint, 
    ScenarioID bigint, 
    [status] varchar(16) 
); 

insert @Master values 
    (425, 'John', 'Skyline'), 
    (426, 'John', 'Violin'), 
    (427, 'Joe', 'Pura'); 
insert @Scenario values 
    (425, 1, 'active'), 
    (425, 2, 'active'), 
    (425, 3, 'done'), 
    (426, 1, 'active'), 
    (426, 2, 'active'), 
    (427, 1, 'done'); 

with ReversedScenarioCTE as 
(
    select 
     ID, 
     [status], 
     rowNumber = row_number() over (partition by ID order by ScenarioID desc) 
    from 
     @Scenario 
) 
select 
    M.ID, 
    M.[user], 
    M.Name, 
    S.[status] 
from 
    @Master M 
    inner join ReversedScenarioCTE S on 
     M.ID = S.ID and 
     S.rowNumber = 1; 
3

Si può fare questo con un CROSS APPLY cercando il più recente per ogni valore:

Select M.ID, M.[User], M.Name, X.Status 
From [Master] M 
Cross Apply 
(
    Select Top 1 S.Status 
    From Scenario S 
    Where S.ID = M.ID 
    Order By S.ScenarioID Desc 
) X 

Un altro modo che si possa fare è con un ROW_NUMBER()PARTITIONED sul ID e ORDERED dal ScenarioIDDESC:

;With OrderedStatuses As 
(
    Select M.Id, M.[User], M.Name, S.Status, 
      Row_Number() Over (Partition By S.Id Order By S.ScenarioID Desc) RN 
    From [Master] M 
    Join Scenario S On S.Id = M.Id 
) 
Select Id, [User], Name, Status 
From OrderedStatuses 
Where RN = 1 
1

Se si dispone di SQL Server 2008 o versione successiva, è possibile utilizzare la funzione ROW_NUMBER() per ottenere ciò che si desidera. Eviterà di interrogare la stessa tabella due volte o eseguire join.

SELECT * 
FROM (

      SELECT a.[user] 
        ,a.ID 
        ,a.Name 
        ,b.status 
        ,ROW_NUMBER() OVER (PARTITION BY a.ID ORDER BY b.scenarioID DESC) AS VersionRank 
      from [master] a INNER JOIN scenario b ON a.ID = b.ID 
     ) Result 
WHERE Result.VersionRank = 1 
+0

Qual è lo scopo del 'DISTINCT' in questa query? –

+0

@JoeFarrell buona domanda Non sospetto nulla, ho semplicemente copiato la query originale dalla domanda e modificata per soddisfare. –

+1

@JoeFarrell Rimosso distinto inutile :) –