web-dev-qa-db-fra.com

SQL Update Multiple Fields FROM via 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 pour ne pas avoir à 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
38
KellCOMnet

Quelque chose comme ça devrait fonctionner (ne peut pas le tester en ce moment - de 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 ça aide?

55
marc_s

Vous devriez pouvoir 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

L'instruction FROM peut être rendue plus optimale (en utilisant des jointures plus spécifiques), mais ce qui précède devrait faire l'affaire. En outre, un avantage agréable de l'écrire de cette façon, pour voir un aperçu de la modification UPDATE UPDATE s SET pour lire SELECT! Vous verrez alors ces données telles qu'elles apparaîtraient si la mise à jour avait eu lieu.

6
Joshua Shannon

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
eKek0

vous pouvez utiliser la mise à jour à partir de ...

quelque chose comme:

mettre à jour le jeu d'expédition .... à partir du chargement interne, joindre ProfilerTest.dbo.BookingDetails sur ...

1
fhranc

J'ai juste eu à résoudre un problème similaire où j'ai ajouté un numéro de séquence (afin que les articles regroupés par ID parent aient une séquence que je peux commander (et vraisemblablement l'utilisateur peut changer le numéro de séquence pour changer la commande).

Dans mon cas, c'est une assurance pour un patient, et l'utilisateur peut définir l'ordre qui lui est attribué, donc le simple fait de 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 est que certaines fonctions d'agrégation ne sont pas autorisées en dehors d'un SELECT

Ce SELECT vous obtient 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 faire correspondre les 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 unique, son codage est toujours simple et la vitesse d'exécution est suffisamment rapide pour plus de 4000 lignes

0
KenF

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 côte à côte) pour vous assurer que ce que je vais mettre à jour est exactement ce que je voulais mettre à jour.

0
HLGEM