条件设置在没有游标的Update语句中

时间:2016-03-02 03:28:44

标签: sql-server tsql

以下循环根据同一个表中是否存在其他记录有条件地设置@EndDate。基本上,如果给定的ReferenceTypeId和每个PersonId,KeepId和RemoveId至少存在一条记录,我们只想将当前日期分配给@EndDate。

如何在没有循环的情况下编写此Update语句。

    DECLARE ReferenceType_Cursor CURSOR FOR  
    SELECT ID FROM CORE.PersonExternalReferenceType 
    OPEN ReferenceType_Cursor   
    FETCH NEXT FROM ReferenceType_Cursor INTO @RefTypeId   

    WHILE @@FETCH_STATUS = 0 
    BEGIN
        SET @ENDDATE = NULL

        IF( EXISTS (SELECT 1 FROM CORE.PersonExternalReferences WHERE ReferenceTypeId = @RefTypeId AND PersonId = @KeepId) AND 
            EXISTS (SELECT 1 FROM CORE.PersonExternalReferences WHERE ReferenceTypeId = @RefTypeId AND PersonId = @RemoveId))
        BEGIN
            SET @ENDDATE     = @CURRENTDATE
        END

        UPDATE CORE.PersonExternalReferences  
        SET  
            PersonId        = @KeepID,
            ModifiedBy      = @USERNAME,
            ModifiedDate    = @CURRENTDATE,
            StartDate       = COALESCE(StartDate,CreatedDate,@STARTDATE),
            EndDate         =  @ENDDATE
        WHERE ReferenceTypeId = @RefTypeId AND PersonId = @RemoveID

    FETCH NEXT FROM ReferenceType_Cursor INTO @RefTypeId
    END
    CLOSE ReferenceType_Cursor   
    DEALLOCATE ReferenceType_Cursor  

3 个答案:

答案 0 :(得分:1)

只是为了澄清你的要求:

您想要更新PersonId = @RemoveID的每个PersonExternalReferences。

对于每个记录,检查是否存在另一个具有相同ReferenceTypeId 和PersonId = @KeepId的PersonExternalReferences 。如果存在,则设置EndDate = @ENDDATE,否则设置EndDate = null。

为了确保它是正常工作的代码,我创建了一个简化的准备运行示例。

架构设置为:

create table PersonExternalReferenceType (
  id varchar(100)
)
go

create table PersonExternalReferences (
  PersonId int,
  ReferenceTypeId varchar(100),
  ModifiedDate datetime,    
  EndDate datetime         
)
go

insert PersonExternalReferenceType
values ('foo'),('bar')
;

insert PersonExternalReferences
values
(1,'foo',null,null),
(2,'foo',null,null),
(3,'foo',null,null),
(4,'bar',null,null)
;

实际的更新声明是

declare @KeepId int   = 1;
declare @RemoveId int = 2;

update PersonExternalReferences
set ModifiedDate = getdate(),
  EndDate = case when exists (
    select 1 from PersonExternalReferences as other
    where other.PersonId = @KeepId 
    and other.ReferenceTypeId = PersonExternalReferences.ReferenceTypeId
  ) then getdate() else null end
where PersonId = @RemoveId;

然后再次使用

运行
declare @KeepId int   = 3;
declare @RemoveId int = 4;

最终结果是

+----------+-----------------+-------------------------+-------------------------+
| PersonId | ReferenceTypeId |      ModifiedDate       |         EndDate         |
+----------+-----------------+-------------------------+-------------------------+
|        1 | foo             | NULL                    | NULL                    |
|        2 | foo             | 2016-03-03 10:27:40.507 | 2016-03-03 10:27:40.507 |
|        3 | foo             | NULL                    | NULL                    |
|        4 | bar             | 2016-03-03 10:27:40.517 | NULL                    |
+----------+-----------------+-------------------------+-------------------------+

答案 1 :(得分:0)

@CURRENTDATE



 UPDATE CORE.PersonExternalReferences  
        SET  
            PersonId        = @KeepID,
            ModifiedBy      = @USERNAME,
            ModifiedDate    = @CURRENTDATE,
            StartDate       = COALESCE(StartDate,CreatedDate,@STARTDATE),
            EndDate         =  
case when (ReferenceTypeId = @RefTypeId 
AND PersonId = @KeepId  
and PersonID = @RemoveId) then 
 @CURRENTDATE 
else null end 
    /*Then you don't need to filter at all if you wanna loop trought whole table...   WHERE ReferenceTypeId = @RefTypeId AND PersonId = @RemoveID
*/




答案 2 :(得分:0)

我有两个解决方案。您只需根据需要编辑分区列和列:

update a
set a.enddate = @enddate
from abc as a
where ReferenceTypeId = @RefTypeId AND PersonId = @RemoveID and
exists(select 1 from abc as b where b.ReferenceTypeId  = a.ReferenceTypeId  group by ReferenceTypeId,PersonId,KeepId,RemoveId  having count(*) >1)

另一个:

update a
set a.enddate = @enddate
from
(
select *, count(*) over (partition by ReferenceTypeId,PersonId,KeepId,RemoveId) as rn
from abc
) as a
where a.rn > 1 and ReferenceTypeId = @RefTypeId AND PersonId = @RemoveID

如果这有帮助,请告诉我。