SQL 基于另一列的最大值对一列进行内部联接
SQL inner join on a column based on max value from another column
我有两个 table,一个 "master" 是名称的主列表,第二个 "scenario" 是主列表中每个名称的多个场景的列表。我希望我的 INNER JOIN
查询从 "scenario" table 中获取具有列状态的 ID 主列表,但仅获取基于 scenarioID 的最新状态。这是我尝试过的代码,tables 具有所需的输出
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
您可以通过 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
另一种方法是在 ID
上使用 ROW_NUMBER()
PARTITIONED
,在 ScenarioID
DESC
上使用 ORDERED
:
;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
如果您有 SQL Server 2008 或更高版本,您可以使用 ROW_NUMBER() 函数来实现您想要的。它将避免查询相同的 table 两次或执行连接。
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
这里有一个使用 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;
我有两个 table,一个 "master" 是名称的主列表,第二个 "scenario" 是主列表中每个名称的多个场景的列表。我希望我的 INNER JOIN
查询从 "scenario" table 中获取具有列状态的 ID 主列表,但仅获取基于 scenarioID 的最新状态。这是我尝试过的代码,tables 具有所需的输出
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
您可以通过 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
另一种方法是在 ID
上使用 ROW_NUMBER()
PARTITIONED
,在 ScenarioID
DESC
上使用 ORDERED
:
;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
如果您有 SQL Server 2008 或更高版本,您可以使用 ROW_NUMBER() 函数来实现您想要的。它将避免查询相同的 table 两次或执行连接。
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
这里有一个使用 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;