【问题标题】:SQL inner join on a column based on max value from another column [duplicate]基于另一列的最大值的列上的 SQL 内连接 [重复]
【发布时间】:2016-09-24 23:57:13
【问题描述】:

我有两个表,一个“主”是名称的主列表,第二个“场景”是主列表中每个名称的多个场景的列表。我希望我的INNER JOIN 查询从“场景”表中获取具有列状态的 ID 主列表,但仅获取基于场景 ID 的最新状态。这是我尝试过的代码和具有所需输出的表格

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)

大师

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

场景

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

期望的输出

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

【问题讨论】:

  • stackoverflow.com/questions/1313120/… 适用于 mysql 而不是 sql server,因此有不同的方法来解决问题。此问题还涉及加入最后一条记录,而重复问题只是试图获取表中的最后一条。

标签: sql sql-server max inner-join where


【解决方案1】:

您可以通过 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

另一种方法是在IDORDERED 上使用ROW_NUMBER() PARTITIONED 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

【讨论】:

    【解决方案2】:

    这是一个稍微不同的公式,它使用 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;
    

    【讨论】:

      【解决方案3】:

      如果您有 SQL Server 2008 或更高版本,您可以使用 ROW_NUMBER() 函数来实现您想要的。它将避免两次查询同一个表或执行连接。

      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
      

      【讨论】:

      • 此查询中DISTINCT 的用途是什么?
      • @JoeFarrell 好问题我没有怀疑,我只是从问题中复制了原始查询并修改以适应。
      • @JoeFarrell 删除了不必要的不​​同 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-21
      • 2023-01-19
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多