如何使用 UPDATE JOIN 从多行更新单行
How to update a single row from multiple rows with UPDATE JOIN
我正在尝试在 SQL Server 2016 中使用 UPDATE JOIN 从多行更新单行。
我有一个 table,其中包含一堆审核事件,如下所示:
Event_Date,Event_Name,Entity_ID
2020-01-01,'USER_ROLE_CHANGED',12345
2020-01-02,'USER_ACCOUNT_ACTIVATED',12345
2020-01-03,'USER"ACCOUNT_DEACTIVATED',12345
用户 table 看起来像这样:
Employee_ID,Employee_Name,Date_Activated,Date_Deactivated,Date_Role_Assigned
12345,'Joe Cool',null,null,null
....
我想将此记录更新为如下所示:
Employee_ID,Employee_Name,Date_Activated,Date_Deactivated,Date_Role_Assigned
12345,'Joe Cool',2020-01-02,2020-01-03,2020-01-01
.....
这是我尝试过的:
update u
set u.date_role_assigned = iif(a.event_name = 'USER_ROLE_CHANGED', a.event_date, u.date_role_assigned),
u.date_activated = iif(a.event_name = 'USER_ACCOUNT_ACTIVATED', a.event_date, u.date_activated),
u.date_deactivated = iif(a.event_name = 'USER_ACCOUNT_DEACTIVATED', a.event_date, u.date_deactivated)
from dbo.[User] u
inner join dbo.AuditEventsPivot a on a.entid = u.empid
然而,我实际上得到了以下信息:
Employee_ID,Employee_Name,Date_Activated,Date_Deactivated,Date_Role_Assigned
12345,'Joe Cool',2020-01-02,null,null
.....
换句话说,它只更新了其中一列,而没有更新另外两列。 (顺便说一下,我确实验证了所讨论 ID 的 table 中存在所有三个事件,所以这不是问题所在 - 问题在于我编写连接本身的方式)。
我可以通过将其拆分为多个查询来解决此问题,但如果可能的话,我更愿意使用单个查询来提高性能并使代码更简洁。 (如果这不会,实际上会导致性能提升,请随时纠正我)。
这可以做到吗,还是我必须将其分成多个查询?
我看过几个相关的问题,但是none直接解决了我的问题;例如,this one 询问如果 JOIN 子句匹配多行会发生什么。基于此(以及类似的问答),我的理解是您不能“指望”它会选择哪一个。不过,我不是问要更新哪一个,我想全部都更新。
我发现一个 Q&A 试图用子查询来做这件事,但这不是我想要做的,因为我想使用 UPDATE JOIN 而不是子查询。
一种方法是预聚合:
update u
set date_role_assigned = coalesce(user_role, u.date_role_assigned)
u.date_role_assigned),
date_activated = coalesce(a.user_account_activated, u.date_activated),
date_deactivated = coalesce(a.user_account_activated, u.date_deactivated)
from dbo.[User] u join
(select a.entid,
max(case when a.event_name = 'USER_ROLE_CHANGED' then a.event_date end) as user_role,
max(case when a.event_name = 'USER_ACCOUNT_ACTIVATED' then a.event_date end) as user_account_activated,
max(case when a.event_name = 'USER_ACCOUNT_DEACTIVATED' then a.event_date end) as user_account_deactivated
from dbo.AuditEventsPivot a
group by a.entid
) a
on a.entid = u.empid;
我正在尝试在 SQL Server 2016 中使用 UPDATE JOIN 从多行更新单行。
我有一个 table,其中包含一堆审核事件,如下所示:
Event_Date,Event_Name,Entity_ID
2020-01-01,'USER_ROLE_CHANGED',12345
2020-01-02,'USER_ACCOUNT_ACTIVATED',12345
2020-01-03,'USER"ACCOUNT_DEACTIVATED',12345
用户 table 看起来像这样:
Employee_ID,Employee_Name,Date_Activated,Date_Deactivated,Date_Role_Assigned
12345,'Joe Cool',null,null,null
....
我想将此记录更新为如下所示:
Employee_ID,Employee_Name,Date_Activated,Date_Deactivated,Date_Role_Assigned
12345,'Joe Cool',2020-01-02,2020-01-03,2020-01-01
.....
这是我尝试过的:
update u
set u.date_role_assigned = iif(a.event_name = 'USER_ROLE_CHANGED', a.event_date, u.date_role_assigned),
u.date_activated = iif(a.event_name = 'USER_ACCOUNT_ACTIVATED', a.event_date, u.date_activated),
u.date_deactivated = iif(a.event_name = 'USER_ACCOUNT_DEACTIVATED', a.event_date, u.date_deactivated)
from dbo.[User] u
inner join dbo.AuditEventsPivot a on a.entid = u.empid
然而,我实际上得到了以下信息:
Employee_ID,Employee_Name,Date_Activated,Date_Deactivated,Date_Role_Assigned
12345,'Joe Cool',2020-01-02,null,null
.....
换句话说,它只更新了其中一列,而没有更新另外两列。 (顺便说一下,我确实验证了所讨论 ID 的 table 中存在所有三个事件,所以这不是问题所在 - 问题在于我编写连接本身的方式)。
我可以通过将其拆分为多个查询来解决此问题,但如果可能的话,我更愿意使用单个查询来提高性能并使代码更简洁。 (如果这不会,实际上会导致性能提升,请随时纠正我)。
这可以做到吗,还是我必须将其分成多个查询?
我看过几个相关的问题,但是none直接解决了我的问题;例如,this one 询问如果 JOIN 子句匹配多行会发生什么。基于此(以及类似的问答),我的理解是您不能“指望”它会选择哪一个。不过,我不是问要更新哪一个,我想全部都更新。
我发现一个 Q&A 试图用子查询来做这件事,但这不是我想要做的,因为我想使用 UPDATE JOIN 而不是子查询。
一种方法是预聚合:
update u
set date_role_assigned = coalesce(user_role, u.date_role_assigned)
u.date_role_assigned),
date_activated = coalesce(a.user_account_activated, u.date_activated),
date_deactivated = coalesce(a.user_account_activated, u.date_deactivated)
from dbo.[User] u join
(select a.entid,
max(case when a.event_name = 'USER_ROLE_CHANGED' then a.event_date end) as user_role,
max(case when a.event_name = 'USER_ACCOUNT_ACTIVATED' then a.event_date end) as user_account_activated,
max(case when a.event_name = 'USER_ACCOUNT_DEACTIVATED' then a.event_date end) as user_account_deactivated
from dbo.AuditEventsPivot a
group by a.entid
) a
on a.entid = u.empid;