如何使用SQL多次更新同一行

时间:2017-05-18 16:19:24

标签: sql sql-server

我在SAM_Updates表中有以下信息

37-529-1    1
13793-1 1
42086-1 1
13793-1 1

我正在运行此查询以更新自定义标签匹配的另一个表(部件)中的数量值。

update Parts 
set Parts.Quantity = cast(cast(Parts.quantity as int) - 
cast(SAMS_Updates.quantity as int) as varchar(100))
from SAMS_Updates
where Parts.SAMS_Custom_Label = SAMS_Updates.Custom_Label

我遇到的问题是值13793.它只是更新从数量中减去一个。我希望它最终减去两个,因为有两个单独的行。

知道为什么会这样吗?我正在使用SQL Server Express。

2 个答案:

答案 0 :(得分:3)

您可以使用联接到聚合QuantitySAM_Updates的子查询:

update p
  set p.Quantity = p.Quantity - su.Quantity
from parts p
  inner join (
    select Custom_Label, sum(cast(Quantity as int)) as Quantity
    from SAMS_Updates 
    group by Custom_Label
    ) su
    on p.SAMS_Custom_Label = su.Custom_Label

rextester演示:http://rextester.com/RTUE81736

假设每个部分在更新之前有10 Quantity,则返回:

+-------------------+----------+
| SAMS_Custom_Label | Quantity |
+-------------------+----------+
| 37-529-1          |        9 |
| 13793-1           |        8 |
| 42086-1           |        9 |
+-------------------+----------+

答案 1 :(得分:0)

这是在基于集合的解决方案上建议使用迭代解决方案的特殊情况之一。这意味着利用(大多数情况下不建议使用)游标操作来一次应用一行修改。基于集合的数据修改方法将在不同的阶段执行,并且直到语句集执行完成后整个集合完成更新之后,才能引用记录的新预期值。

虽然包含对每个零件分组的汇总数量的子查询将实现对零件库存数量进行修改的基本任务,但它不能确保每个数据驱动的更新均已完成且不会在随后执行的零件库存更新过程中重新应用。

但是,请注意,使用游标可能需要其他注意事项,以适当地调整查询,以减轻因其相关的较高开销而对性能造成的潜在影响。

以下代码概述了如何使用SQL游标多次更新同一行:

/*Create Base Tables*/
    /*Parts Table*/
        /*Create Table*/
            drop table if exists #parts
            create table #parts
                (idParts bigint identity(1, 1) not null,
                SAMS_Custom_Label varchar(25) primary key not null,
                Quantity int not null default 0 check(Quantity >= 0))  --check assumes backorder logic is separate

        /*Insert Values*/
            insert into #parts
                (SAMS_Custom_Label,
                Quantity)
            values  ('37-529-1', 5),
                    ('13793-1', 5),
                    ('42086-1', 5)

        /*Review Current Parts Quantities*/
            select P.SAMS_Custom_Label,
                P.Quantity
            from #parts P

    /*SAM_Updates Table*/
        /*Create Table*/
            drop table if exists #SAM_Updates
            create table #SAM_Updates
                (idSAM_Updates bigint identity(1, 1) primary key not null,
                Custom_Label varchar(25) not null,  --the #parts table should be reference for referential integrity
                Quantity int not null check(Quantity <> 0),
                partsQuantityUpdated bit not null default 'false')  --Indicates Quantity Update was applied to #parts table

        /*Insert Values*/
            insert into #SAM_Updates
                (Custom_Label,
                Quantity)
            values  ('37-529-1', 1),
                    ('13793-1', 1),
                    ('42086-1', 1),
                    ('13793-1', 1)


/*Parts Inventory Update Process*/
    /*Setup Cursor*/
        /*Operational parms*/
            declare @idSAM_Updates bigint,
                @Custom_Label varchar(25),
                @Quantity int

        /*Create & Open Cursor record set*/
            DECLARE C CURSOR
            FOR (   select SU.idSAM_Updates,
                        SU.Custom_Label,
                        SU.Quantity
                    from #SAM_Updates SU
                    where SU.partsQuantityUpdated = 'false')  --Apply only updates that haven't been performed
            OPEN C

        /*Initiate first fetch record*/
            FETCH NEXT
            FROM C
            INTO @idSAM_Updates,
                @Custom_Label,
                @Quantity


        /*Perform Loop*/
            WHILE @@FETCH_STATUS = 0  
                BEGIN
                    /*Apply difference to Parts Inventory Quantity*/
                        update P
                        set P.Quantity = P.Quantity - @Quantity
                        from #parts P
                        where P.SAMS_Custom_Label = @Custom_Label

                    /*Mark current SAM_Updates record as applied to #parts table*/
                        update SU
                        set SU.partsQuantityUpdated = 'true'
                        from #SAM_Updates SU
                        where SU.idSAM_Updates = @idSAM_Updates

                    /*Initiate next fetch record*/
                        FETCH NEXT
                        FROM C
                        INTO @idSAM_Updates,
                            @Custom_Label,
                            @Quantity
                END

        /*Close Cursor*/
            CLOSE C
            DEALLOCATE C


/*Examine Results*/
    /*Updated Parts Quantities*/
        select P.SAMS_Custom_Label,
            P.Quantity
        from #parts P


/*new records added to the #SAM_Updates table will be applied to the parts inventory each time the Parts Inventory Update Process is reran*/