基于另一列的最大值的列上的SQL内连接

oba*_*abs 5 sql sql-server inner-join max where

我有两个表,一个"主"是主列表的名称,第二个"方案"是主列表中每个名称的多个方案的列表.我希望我的INNER JOIN查询从"scenario"表中获取具有列状态的ID的主列表,但仅获取基于scenarioID的最新状态.这是我尝试的代码和具有所需输出的表

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)
Run Code Online (Sandbox Code Playgroud)

ID    user    Name
425   John    Skyline
426   John    Violin
427   Joe     Pura
Run Code Online (Sandbox Code Playgroud)

脚本

ID    ScenarioID    status
425   1             active
425   2             active
425   3             done
426   1             active
426   2             active
427   1             done
Run Code Online (Sandbox Code Playgroud)

期望的输出

ID    user    Name    status
425   John    Skyline done
426   John    Violin  active
427   Joe     Pura    done
Run Code Online (Sandbox Code Playgroud)

Siy*_*ual 5

您可以通过CROSS APPLY查找每个值的最新值来执行此操作:

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
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用 a ROW_NUMBER() PARTITIONEDon theIDORDEREDby ScenarioID 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
Run Code Online (Sandbox Code Playgroud)


Joe*_*ell 1

这是使用 CTE 的稍微不同的公式,我通常发现它比子查询更容易阅读(当然,您的情况可能会有所不同)。

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;
Run Code Online (Sandbox Code Playgroud)