通过SELECT语句更新多个字段的SQL方法

44
这个方法可行,但我希望消除冗余。是否有一种方法可以将更新与单个选择语句合并,以便我不必使用变量?
    DECLARE
        @OrgAddress1 varchar,
        @OrgAddress2 varchar,
        @OrgCity varchar,
        @OrgState varchar,
        @OrgZip varchar,
        @DestAddress1 varchar,
        @DestAddress2 varchar,
        @DestCity varchar,
        @DestState varchar,
        @DestZip varchar

    SELECT 
        @OrgAddress1    =   OrgAddress,
        @OrgAddress2    =   OrgAddress2,
        @OrgCity        =   OrgCity,
        @OrgState       =   OrgState,
        @OrgZip         =   OrgZip,
        @DestAddress1   =   DestAddress,
        @DestAddress2   =   DestAddress2,
        @DestCity       =   DestCity,
        @DestState      =   DestState,
        @DestZip        =   DestZip
    FROM 
        ProfilerTest.dbo.BookingDetails 
    WHERE 
        MyID=@MyID

    UPDATE SHIPMENT
    SET
        OrgAddress1     =   @OrgAddress1,
        OrgAddress2     =   @OrgAddress2,
        OrgCity         =   @OrgCity,
        OrgState        =   @OrgState,
        OrgZip          =   @OrgZip,
        DestAddress1    =   @DestAddress1,
        DestAddress2    =   @DestAddress2,
        DestCity        =   @DestCity,
        DestState       =   @DestState,
        DestZip         =   @DestZip
    WHERE 
        MyID2=@ MyID2
6个回答

62

这样的代码应该可以解决问题(我现在无法测试,只是从记忆中重现):

UPDATE SHIPMENT
SET
  OrgAddress1     = BD.OrgAddress1,
  OrgAddress2     = BD.OrgAddress2,
  OrgCity         = BD.OrgCity,
  OrgState        = BD.OrgState,
  OrgZip          = BD.OrgZip,
  DestAddress1    = BD.DestAddress1,
  DestAddress2    = BD.DestAddress2,
  DestCity        = BD.DestCity,
  DestState       = BD.DestState,
  DestZip         = BD.DestZip
FROM
   BookingDetails BD
WHERE 
   SHIPMENT.MyID2 = @MyID2
   AND
   BD.MyID = @MyID

那有帮助吗?


运行得非常好,我知道必须有一种基于选择语句进行更新的方法,但是我不知道该如何实现。 - KellCOMnet
1
FYI - 这在 Oracle 中不起作用。相反,您可以使用以下代码: <code> update ( select table1.field1 as a1 , table2.field2 as b1 from table1, table2 where field1 = field2) set a1 = b1 注意:如果您的字段出于某种原因具有相同的名称,则我认为别名是必要的。 - Jody
3
@Jody:这个问题是关于SQL Server的,而不是Oracle,所以我提供了在SQL Server中有效的解决方案。 - marc_s
@marc_s 但是JODY告知其他人有关ORACLE是很好的。 - Ibrahim Oudah
@IbrahimOudah的回答告诉了我该怎么做,Jody的评论解释了为什么我之前没看到过这种语法。 - JollyJoker

9

您可以使用:

UPDATE s SET
  s.Field1 = q.Field1,
  s.Field2 = q.Field2,
  (list of fields...)
FROM (
  SELECT Field1, Field2, (list of fields...)
  FROM ProfilerTest.dbo.BookingDetails 
  WHERE MyID=@MyID
) q
WHERE s.MyID2=@ MyID2

7
您应该能够按照以下步骤进行操作:
UPDATE s
SET
    OrgAddress1 = bd.OrgAddress1,
    OrgAddress2 = bd.OrgAddress2,
    ...
    DestZip = bd.DestZip
FROM
    Shipment s, ProfilerTest.dbo.BookingDetails bd
WHERE
    bd.MyID = @MyId AND s.MyID2 = @MyID2

FROM语句可以更优化(使用更具体的连接方式),但上述方法应该可以解决问题。此外,以这种方式编写的一个不错的附带好处是,将UPDATE s SET改为SELECT,就可以预览更新后的数据!然后,您将看到数据的更新情况。


同样的区别。这对我来说更清晰。我没有进行双重选择。我只会得到从FROM子句中出现的s结果。 - Joshua Shannon
为什么在更新后没有立即指定Shipment,而是在FROM子句中指定的问题。Marc_s在上面的答案中解释了这个问题,在MSSQL中实际上具有完全相同的执行计划。 - Joshua Shannon

0

我刚刚解决了一个类似的问题,我添加了一个序列号(这样按父ID分组的项目就有了一个可以排序的序列号(用户可以更改序列号以更改排序)。

在我的情况下,这是患者的保险,用户可以设置他们被分配的顺序,因此仅按主键进行排序对于长期来说并不有用,但对于设置默认值很有用。

所有其他解决方案的问题在于某些聚合函数不允许在SELECT之外使用。

这个SELECT语句可以获得新的序列号:

select PatientID,
       PatientInsuranceID, 
       Sequence, 
       Row_Number() over(partition by PatientID order by PatientInsuranceID) as RowNum
from PatientInsurance
order by PatientID, PatientInsuranceID

这个更新命令本来很简单,但是被禁止了:

update PatientInsurance
set Sequence = Row_Number() over(partition by PatientID order by PatientInsuranceID)

解决方案(我刚刚做了),与eKek0的解决方案类似:

UPDATE PatientInsurance
SET  PatientInsurance.Sequence = q.RowNum
FROM (select PatientInsuranceID, 
             Row_Number() over(partition by PatientID order by PatientInsuranceID) as RowNum
      from PatientInsurance
     ) as q 
WHERE PatientInsurance.PatientInsuranceID=q.PatientInsuranceID 

这让我可以选择需要匹配的ID和需要为该ID设置的值。如果我没有使用Row_Number(),其他解决方案也可以。但是,Row_Number()在SELECT之外不起作用。

考虑到这是一次性操作,它的编码仍然很简单,并且运行速度足够快,可以处理4000多行数据。


0

我会这样写

UPDATE s
SET    OrgAddress1 = bd.OrgAddress1,    OrgAddress2 = bd.OrgAddress2,    
     ...    DestZip = bd.DestZip
--select s.OrgAddress1, bd.OrgAddress1, s.OrgAddress2, bd.OrgAddress2, etc 
FROM    Shipment s
JOIN ProfilerTest.dbo.BookingDetails bd on  bd.MyID =s.MyID2
WHERE    bd.MyID = @MyId 

这种方式使连接显式化,因为我认为隐式连接是不好的。您可以运行已注释的选择(通常我指定要更新的字段旧值和新值并排),以确保我要更新的内容正是我想要更新的。


我不确定在原始示例中BookingDetails和Shipment之间是否存在bd.MyID和s.MyID2的一对一(或多对一)关系。给定的示例有(我承认,我假设)两个不同的参数用于IDs,因此我假设它们有可能是不同的。但我同意,如果存在明确的连接,那么应该使用它! - Joshua Shannon
甚至没有注意到这一点,因此交叉连接可能是更好的解决方案。只有原帖作者知道确切情况。 - HLGEM

0

您可以使用以下语句进行更新:

update shipment set.... from shipment inner join ProfilerTest.dbo.BookingDetails on ...

类似这样的语句。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接