SQL met à jour plusieurs champs à partir d'une instruction SELECT

Cela fonctionne, mais je voudrais supprimer la redondance. Existe-t-il un moyen de fusionner la mise à jour avec une seule instruction select, donc je n'ai pas besoin d'utiliser vars?

    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
33
demandé sur Juan Mellado 2009-08-12 22:45:54

6 réponses

Quelque chose comme ça devrait fonctionner (ne peut pas le tester en ce moment-de la mémoire):

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

Est-ce que c'?

51
répondu marc_s 2013-05-06 04:56:08

Vous devriez être capable de faire quelque chose dans le sens de ce qui suit

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 statement peut être rendu plus optimial (en utilisant des jointures plus spécifiques), mais ce qui précède devrait faire l'affaire. Aussi, un bon avantage de côté à l'écrire de cette façon, pour voir un aperçu de la mise à jour change UPDATE s SET à lire SELECT! Vous verrez alors ces données telles qu'elles apparaîtraient si la mise à jour avait eu lieu.

6
répondu Joshua Shannon 2009-08-12 19:39:43

Vous pouvez utiliser:

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
5
répondu eKek0 2011-12-21 19:12:05

Vous pouvez utiliser update from...

Quelque Chose comme:

Mettre à jour le jeu d'expédition.... de envoi INNER join ProfilerTest.dbo.BookingDetails sur ...

1
répondu 2009-08-12 18:52:18

Je l'écrirais de cette façon

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 

De cette façon, la jointure est explicite car les jointures implicites sont une mauvaise chose à mon humble avis. Vous pouvez exécuter la sélection commentée (généralement je spécifie les champs que je mets à jour les anciennes et les nouvelles valeurs les unes à côté des autres) pour vous assurer que ce que je vais mettre à jour est exactement ce que je voulais mettre à jour.

0
répondu HLGEM 2009-08-12 19:55:07

J'ai juste dû résoudre un problème similaire où j'ai ajouté un numéro de séquence (de sorte que les éléments regroupés par un ID parent, ont une séquence que je peux commander (et vraisemblablement l'utilisateur peut changer le numéro de séquence pour changer l'ordre).

Dans mon cas, c'est une assurance pour un Patient, et l'utilisateur peut définir l'ordre dans lequel il est assigné, donc passer par la clé primaire n'est pas utile à long terme, mais est utile pour définir une valeur par défaut.

Le problème avec toutes les autres solutions que certaines fonctions d'agrégat ne sont pas autorisées en dehors D'un SELECT

Cette sélection vous donne le nouveau numéro de Séquence:

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

Cette commande de mise à jour, serait simple, mais n'est pas autorisée:

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

La solution qui a fonctionné (je viens de le faire), et est similaire à la solution d'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 

Cela me permet de sélectionner l'ID dont j'ai besoin pour correspondre aux choses, et la valeur que je dois définir pour cet ID. D'autres solutions auraient été bien si je n'utilisais pas Row_Number () qui ne fonctionnera pas en dehors d'un SELECT.

Étant donné qu'il s'agit d'une opération 1 fois, le codage est toujours simple, et la vitesse d'exécution est assez rapide pour plus de 4000 lignes

0
répondu KenF 2017-10-09 16:02:44