Requête de mise à jour SQL à l'aide de jointures

664

Je dois mettre à jour un champ avec une valeur qui est retournée par une jointure de 3 tables.

Exemple:

select
    im.itemid
    ,im.sku as iSku
    ,gm.SKU as GSKU
    ,mm.ManufacturerId as ManuId
    ,mm.ManufacturerName
    ,im.mf_item_number
    ,mm.ManufacturerID
from 
    item_master im, group_master gm, Manufacturer_Master mm 
where
    im.mf_item_number like 'STA%'
    and im.sku=gm.sku
    and gm.ManufacturerID = mm.ManufacturerID
    and gm.manufacturerID=34

Je veux mettre à jour les mf_item_numbervaleurs de champ de la table item_masteravec une autre valeur qui est jointe dans la condition ci-dessus.

Comment puis-je faire cela dans MS SQL Server?

Shyju
la source
124
Veuillez cesser d'utiliser ces jointures implicites pour commencer. C'est une mauvaise technique qui conduit à des résultats incorrects en raison de jointures croisées inattendues. Ce style de code est obsolète depuis 18 ans
HLGEM
2
Voir aussi SO question ... stackoverflow.com/questions/1293330/…
SteveC

Réponses:

1251
UPDATE im
SET mf_item_number = gm.SKU --etc
FROM item_master im
JOIN group_master gm
    ON im.sku = gm.sku 
JOIN Manufacturer_Master mm
    ON gm.ManufacturerID = mm.ManufacturerID
WHERE im.mf_item_number like 'STA%' AND
      gm.manufacturerID = 34

Pour être clair ... La UPDATEclause peut faire référence à un alias de table spécifié dans la FROMclause. Donc, imdans ce cas, est valide

Exemple générique

UPDATE A
SET foo = B.bar
FROM TableA A
JOIN TableB B
    ON A.col1 = B.colx
WHERE ...
gbn
la source
9
Postgres se plaint UPDATE im; im est un alias que Postgres ne reconnaît pas: /
fatuhoku
10
Pour info cela ne fonctionnera PAS dans MySQL (syntaxe différente)! Pour MySQL, jetez un œil à la réponse de
gcbenison
67

L'un des moyens les plus simples consiste à utiliser une expression de table commune (puisque vous êtes déjà sur SQL 2005):

with cte as (
select
    im.itemid
    ,im.sku as iSku
    ,gm.SKU as GSKU
    ,mm.ManufacturerId as ManuId
    ,mm.ManufacturerName
    ,im.mf_item_number
    ,mm.ManufacturerID
    , <your other field>
from 
    item_master im, group_master gm, Manufacturer_Master mm 
where
    im.mf_item_number like 'STA%'
    and im.sku=gm.sku
    and gm.ManufacturerID = mm.ManufacturerID
    and gm.manufacturerID=34)
update cte set mf_item_number = <your other field>

Le moteur d'exécution des requêtes trouvera par lui-même comment mettre à jour l'enregistrement.

Remus Rusanu
la source
8
Excellent, l'utilisation du CTE facilite la conversion du SELECT d'origine en MISE À JOUR
SteveC
4
Fonctionne tant que votre requête SELECT n'a pas d'agrégats, DISTINCT, etc.
Baodad
1
Je commence généralement par un point-virgule pour terminer la déclaration précédente (le cas échéant). CTE roches! Conception simple de requêtes compliquées / mises à jour jointes. Je l'utilise tout le temps ...
Adam W
64

L'adaptation à MySQL - il n'y a pas de FROMclause UPDATE, mais cela fonctionne:

UPDATE
    item_master im
    JOIN
    group_master gm ON im.sku=gm.sku 
    JOIN
    Manufacturer_Master mm ON gm.ManufacturerID=mm.ManufacturerID
SET
    im.mf_item_number = gm.SKU --etc
WHERE
    im.mf_item_number like 'STA%'
    AND
    gm.manufacturerID=34
gcbenison
la source
12

N'a pas utilisé votre sql ci-dessus mais voici un exemple de mise à jour d'une table basée sur une instruction join.

UPDATE p
SET    p.category = c.category
FROM   products p
       INNER JOIN prodductcatagories pg
            ON  p.productid = pg.productid
       INNER JOIN categories c
            ON  pg.categoryid = c.cateogryid
WHERE  c.categories LIKE 'whole%'
Gratzy
la source
8

Vous pouvez spécifier des tables supplémentaires utilisées pour déterminer comment et quoi mettre à jour avec la clause "FROM" dans l'instruction UPDATE, comme ceci:

update item_master
set mf_item_number = (some value)
from 
   group_master as gm
   join Manufacturar_Master as mm ON ........
where
 .... (your conditions here)

Dans la clause WHERE, vous devez fournir les conditions et les opérations de jointure pour lier ces tables entre elles.

Marc

marc_s
la source
5
..ou utilisez ANSI JOINS dans la clause FROM
gbn
5
Oui, veuillez utiliser les jointures ansi, vous pourriez avoir de réels problèmes dans une mise à jour si vous avez accidentellement obtenu une jointure croisée.
HLGEM
7

MySQL: En général, faites les changements nécessaires selon vos besoins:

UPDATE
    shopping_cart sc
    LEFT JOIN
    package pc ON sc. package_id = pc.id    
SET
    sc. amount = pc.amount
Vinod Joshi
la source
3

Essayez comme ça ...

Update t1.Column1 = value 
from tbltemp as t1 
inner join tblUser as t2 on t2.ID = t1.UserID 
where t1.[column1]=value and t2.[Column1] = value;
Ankitkumar Tandel
la source
2

Vous pouvez utiliser la requête suivante:

UPDATE im
SET mf_item_number = (some value) 
FROM item_master im
JOIN group_master gm
    ON im.sku = gm.sku 
JOIN Manufacturer_Master mm
    ON gm.ManufacturerID = mm.ManufacturerID
WHERE im.mf_item_number like 'STA%' AND
      gm.manufacturerID = 34    `sql`
Prasan Karunarathna
la source
1

Vous pouvez mettre à jour avec MERGECommand avec beaucoup plus de contrôle MATCHEDet NOT MATCHED: (J'ai légèrement changé le code source pour démontrer mon point)

USE tempdb;
GO
IF(OBJECT_ID('target') > 0)DROP TABLE dbo.target
IF(OBJECT_ID('source') > 0)DROP TABLE dbo.source
CREATE TABLE dbo.Target
    (
      EmployeeID INT ,
      EmployeeName VARCHAR(100) ,
      CONSTRAINT Target_PK PRIMARY KEY ( EmployeeID )
    );
CREATE TABLE dbo.Source
    (
      EmployeeID INT ,
      EmployeeName VARCHAR(100) ,
      CONSTRAINT Source_PK PRIMARY KEY ( EmployeeID )
    );
GO
INSERT  dbo.Target
        ( EmployeeID, EmployeeName )
VALUES  ( 100, 'Mary' );
INSERT  dbo.Target
        ( EmployeeID, EmployeeName )
VALUES  ( 101, 'Sara' );
INSERT  dbo.Target
        ( EmployeeID, EmployeeName )
VALUES  ( 102, 'Stefano' );

GO
INSERT  dbo.Source
        ( EmployeeID, EmployeeName )
VALUES  ( 100, 'Bob' );
INSERT  dbo.Source
        ( EmployeeID, EmployeeName )
VALUES  ( 104, 'Steve' );
GO

SELECT * FROM dbo.Source
SELECT * FROM dbo.Target

MERGE Target AS T
USING Source AS S
ON ( T.EmployeeID = S.EmployeeID )
WHEN MATCHED THEN
    UPDATE SET T.EmployeeName = S.EmployeeName + '[Updated]';
GO 
SELECT '-------After Merge----------'
SELECT * FROM dbo.Source
SELECT * FROM dbo.Target
Yashar Aliabbasi
la source