2016-05-26 11 views
5

Ich habe zwei Tabellen, ein "Master" ist eine Master-Liste von Namen und das zweite "Szenario" ist eine Liste von mehreren Szenarien für jeden Namen aus der Master-Liste . Ich möchte, dass meine INNER JOIN-Abfrage die Master-ID-Liste mit dem Spaltenstatus aus der Tabelle "scenario" abruft, aber nur den neuesten Status basierend auf szearID. Hier ist der Code, den ich versucht habe und Tabellen mit den gewünschten AusgangSQL Inner Join auf einer Spalte basierend auf Max Wert aus einer anderen Spalte

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) 

Meister

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

Szenario

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

Wunsch Ausgang

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 ist für MySQL nicht SQL-Server, so gibt es verschiedene Möglichkeiten, das Problem zu lösen. Auch diese Frage bezieht sich auf den letzten Datensatz, während die doppelte Frage versucht, den letzten innerhalb einer Tabelle zu erhalten. –

Antwort

1

Hier ist eine etwas andere Formulierung, die einen CTE verwendet, die ich als eine Unterabfrage zu lesen im Allgemeinen einfacher zu finden (obwohl natürlich die Leistung kann variieren).

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

Sie dies mit einem CROSS APPLY tun können, die aktuellste für jeden Wert aufzublicken:

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 

Eine weitere Möglichkeit, es ist mit einem ROW_NUMBER()PARTITIONED auf dem ID und ORDERED durch die ScenarioID tun konnte DESC:

;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

Wenn Sie SQL Server 2008 oder höher haben, können Sie die Funktion ROW_NUMBER() verwenden, um zu erreichen, was Sie wollen. Es wird vermieden, die gleiche Tabelle zweimal abzufragen oder Joins durchzuführen.

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

Was ist der Zweck der "DISTINCT" in dieser Abfrage? –

+0

@JoeFarrell gute Frage Ich vermute nichts, ich habe einfach die ursprüngliche Abfrage von der Frage kopiert und geändert, um zu passen. –

+1

@JoeFarrell Unnötiges distinct entfernt :) –