请求协助:SQL Server中按规则更新activity_date字段的问题
解决ACTIVITY_LOG中3721类型记录日期更新的SQL问题
先来看你的场景和需求:
你有这样的ACTIVITY_LOG示例数据:
[IND_ID] [ACTIVITY_TYPE] [ACTIVITY_DATE] 100 3770 12/12/2014 100 3721 Null 103 3771 21/06/2017 103 3721 Null 122 3770 07/07/2017 122 3721 Null
你的需求是:找到所有同时存在activity_type=3721和activity_type为3770/3771的IND_ID,把这些IND_ID下activity_type=3721的ACTIVITY_DATE,更新为对应IND_ID的3770或3771的日期值。
你之前写的SQL不生效,先看看你原来的代码:
declare @actiondate DATETIME, @ind_ref int SET @actiondate = (select ACTION_DATE from ACTIVITY_LOG where activity_type in (3770,3771) and INDIVIDUAL_REF=@ind_ref) UPDATE ACTIVITY_LOG SET ACTION_DATE= ( CASE WHEN ACTIVITY_TYPE='3721' AND ACTION_DATE IS NULL AND ACTIVITY_LOG.INDIVIDUAL_REF=@ind_ref THEN @actiondate ELSE ACTION_DATE END) FROM ACTIVITY_LOG
为什么原来的SQL不生效?
问题出在这几个点:
@ind_ref变量没有赋值,是空值,导致子查询找不到对应日期,@actiondate也会是NULL- 这种单变量的写法只能处理单个
IND_ID,没办法批量处理所有符合条件的记录 - 你在CASE里用了
ACTIVITY_TYPE='3721',但示例里3721是数字类型,加单引号会触发隐式转换,可能引发异常或匹配错误
正确的批量更新SQL写法
我们可以用自连接的方式实现批量更新,直接关联同一个表中对应IND_ID的3770/3771记录:
UPDATE al_target SET al_target.ACTIVITY_DATE = al_source.ACTIVITY_DATE FROM ACTIVITY_LOG al_target JOIN ACTIVITY_LOG al_source ON al_target.IND_ID = al_source.IND_ID AND al_source.ACTIVITY_TYPE IN (3770, 3771) WHERE al_target.ACTIVITY_TYPE = 3721 AND al_target.ACTIVITY_DATE IS NULL
逻辑解释:
- 把
ACTIVITY_LOG拆成两个逻辑表:al_target是要更新的目标(3721类型的空日期记录),al_source是提供日期来源的表(3770/3771类型的记录) - 通过
IND_ID关联两个表,确保是同一个个体的记录 - WHERE条件精准筛选出需要更新的目标记录
- 直接将来源表的日期赋值给目标表的日期字段
如果一个IND_ID同时存在3770和3771的记录,你可以用ROW_NUMBER()指定优先取最新的日期:
WITH source_dates AS ( SELECT IND_ID, ACTIVITY_DATE, -- 按日期倒序,取每个IND_ID的最新日期记录 ROW_NUMBER() OVER (PARTITION BY IND_ID ORDER BY ACTIVITY_DATE DESC) AS rn FROM ACTIVITY_LOG WHERE ACTIVITY_TYPE IN (3770, 3771) ) UPDATE al_target SET al_target.ACTIVITY_DATE = sd.ACTIVITY_DATE FROM ACTIVITY_LOG al_target JOIN source_dates sd ON al_target.IND_ID = sd.IND_ID AND sd.rn = 1 -- 只取每个IND_ID的最新日期 WHERE al_target.ACTIVITY_TYPE = 3721 AND al_target.ACTIVITY_DATE IS NULL
内容的提问来源于stack exchange,提问作者Biswa
相关产品推荐
相关产品推荐

