Comment puis-je faire une instruction UPDATE avec JOIN dans SQL Server?

1314

J'ai besoin de mettre à jour cette table dans SQL Server avec les données de sa table «parent», voir ci-dessous:

Tableau: vente

id (int)
udid (int)
assid (int)

Tableau: ud

id  (int)
assid  (int)

sale.assidcontient la valeur correcte à mettre à jour ud.assid.

Quelle requête fera cela? Je pense à un joinmais je ne sais pas si c'est possible.

Ant Swift
la source
3
Quel SGBDR utilisez-vous? MySQL, SQL Server, Oracle, PostgreSQL ou autre chose?
Chris J
quelques relations entre les tables? Comment savoir quel disque de vente correspond à quel disque de ud? Est-il basé sur id comme clé primaire dans les deux tables?
Cătălin Pitiș
Comment mettre à jour UD? Il n'a que l'assid et sa propre ID. Pourriez-vous donner un exemple en termes de valeurs réelles qui existent et les enregistrements que vous souhaitez modifier ou ajouter à la suite du script?
Bernhard Hofmann
2
Alias ​​d'utilisateur dans une requête comme stackoverflow.com/questions/982919/sql-update-query-using-joins
Imran Muhammad

Réponses:

2383

La syntaxe dépend strictement du SGBD SQL que vous utilisez. Voici quelques façons de le faire dans ANSI / ISO (aka devrait fonctionner sur n'importe quel SGBD SQL), MySQL, SQL Server et Oracle. Soyez avisé que ma méthode ANSI / ISO suggérée sera généralement beaucoup plus lente que les deux autres méthodes, mais si vous utilisez un SGBD SQL autre que MySQL, SQL Server ou Oracle, alors c'est peut-être la seule voie à suivre (par exemple si votre SGBD SQL ne prend pas en charge MERGE):

ANSI / ISO:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where exists (
      select * 
      from sale 
      where sale.udid = ud.id
 );

MySQL:

update ud u
inner join sale s on
    u.id = s.udid
set u.assid = s.assid

Serveur SQL:

update u
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid

PostgreSQL:

update ud
  set assid = s.assid
from sale s 
where ud.id = s.udid;

Notez que la table cible ne doit pas être répétée dans la FROMclause pour Postgres.

Oracle:

update
    (select
        u.assid as new_assid,
        s.assid as old_assid
    from ud u
        inner join sale s on
            u.id = s.udid) up
set up.new_assid = up.old_assid

SQLite:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where RowID in (
      select RowID 
      from ud 
      where sale.udid = ud.id
 );
Eric
la source
3
Il me semble que MySQL set assid = s.assiddevrait l'être set u.assid = s.assid.
dotancohen
2
Dans la syntaxe ANSI, que se passe-t-il si SELECT après le =retourne plus d'une ligne?
Compte à jeter
2
@ ThrowawayAccount3Million Cela échouerait probablement. AFAIK, ce type d'opération attendrait une valeur scalaire et générera une erreur si on lui donne un jeu de résultats à la place.
Francis Lord
6
Je souhaite que l'OP choisisse de meilleurs noms pour sa table et ses colonnes !! ce n'est pas si lisible / intuitif ...
S.Serpooshan
4
Postgre 9.3 ne fonctionnait qu'avecupdate ud set assid = s.assid
StackUnder
143

Cela devrait fonctionner dans SQL Server:

update ud 
set assid = sale.assid
from sale
where sale.udid = id
edosoft
la source
98

postgres

UPDATE table1
SET    COLUMN = value
FROM   table2,
       table3
WHERE  table1.column_id = table2.id
       AND table1.column_id = table3.id
       AND table1.COLUMN = value
       AND table2.COLUMN = value
       AND table3.COLUMN = value 
user1154043
la source
20
La réponse serait plus pratique si elle utilisait les noms de table / colonne utilisés dans la question. Pourquoi y a-t-il 3 tableaux dans votre réponse?
alfonx
50

Une approche SQL standard serait

UPDATE ud
SET assid = (SELECT assid FROM sale s WHERE ud.id=s.id)

Sur SQL Server, vous pouvez utiliser une jointure

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id
MattH
la source
1
Avec la première, vous ne pouvez pas faire de correspondance sur plus de 2 colonnes, mais rejoindre fonctionne très bien.
makciook
6
@makciook: hein? Vous pouvez simplement ajouter plus de conditions dans la WHEREclause si vous souhaitez faire correspondre des colonnes supplémentaires.
siride
2
Juste un peu ... mais je pense que l'OP signifiait sale.udid = ud.id. Et pas sale.id.
Skippy VonDrake
39

PostgreSQL :

CREATE TABLE ud (id integer, assid integer);
CREATE TABLE sales (id integer, udid integer, assid integer);

UPDATE ud
SET assid = sales.assid
FROM sales
WHERE sales.id = ud.id;
Alfonx
la source
26

Requête de mise à jour simplifiée utilisant JOIN -ing plusieurs tables.

   UPDATE
        first_table ft
        JOIN second_table st ON st.some_id = ft.some_id
        JOIN third_table tt  ON tt.some_id = st.some_id
        .....
    SET
        ft.some_column = some_value
    WHERE ft.some_column = 123456 AND st.some_column = 123456

Remarque - first_table, second_table, third_table et some_column comme 123456 sont des noms de table de démonstration, des noms de colonne et des identifiants. Remplacez-les par les noms valides.

Vinit Kadkol
la source
16

Un autre exemple pourquoi SQL n'est pas vraiment portable.

Pour MySQL, ce serait:

update ud, sale
set ud.assid = sale.assid
where sale.udid = ud.id;

Pour plus d'informations, lisez la mise à jour de plusieurs tables: http://dev.mysql.com/doc/refman/5.0/en/update.html

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
    [WHERE where_condition]
Yada
la source
2
+1 sur le commentaire "pourquoi SQL n'est pas vraiment portable"! La portabilité est si fragile que la simple déclaration d'une variable interrompra la portabilité entre de nombreux moteurs de base de données populaires.
Jeff Moden
8

Teradata Aster offre une autre façon intéressante d'atteindre l'objectif:

MERGE INTO ud --what trable should be updated
USING sale -- from what table/relation update info should be taken
ON ud.id = sale.udid --join condition
WHEN MATCHED THEN 
    UPDATE SET ud.assid = sale.assid; -- how to update
xhudik
la source
8

Je pensais que celui de SQL-Server dans le post supérieur fonctionnerait pour Sybase car ils sont tous les deux T-SQL mais malheureusement pas.

Pour Sybase, j'ai trouvé que la mise à jour doit être sur la table elle-même et non sur l'alias:

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid
Ken Goh
la source
7

L'instruction suivante avec le mot clé FROM est utilisée pour mettre à jour plusieurs lignes avec une jointure

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division
Sheryar Nizar
la source
7

MySQL

Vous obtiendrez les meilleures performances si vous oubliez la clause where et placez toutes les conditions dans l'expression ON.

Je pense que c'est parce que la requête doit d'abord rejoindre les tables, puis exécute la clause where à ce sujet, donc si vous pouvez réduire ce qui est nécessaire pour rejoindre, c'est la manière rapide d'obtenir les résultats / faire la mise à jour.

Exemple

Scénario

Vous avez une table d'utilisateurs. Ils peuvent se connecter en utilisant leur nom d'utilisateur ou leur adresse e-mail ou leur numéro de compte. Ces comptes peuvent être actifs (1) ou inactifs (0). Ce tableau comporte 50000 lignes

Vous avez ensuite un tableau d'utilisateurs à désactiver en une seule fois, car vous découvrez qu'ils ont tous fait quelque chose de mal. Ce tableau contient cependant une colonne avec des noms d'utilisateur, des e-mails et des numéros de compte mélangés. Il a également un indicateur "has_run" qui doit être mis à 1 (vrai) quand il a été exécuté

Requete

UPDATE users User
    INNER JOIN
        blacklist_users BlacklistUser
        ON
        (
            User.username = BlacklistUser.account_ref
            OR
            User.email = BlacklistedUser.account_ref
            OR
            User.phone_number = BlacklistUser.account_ref
            AND
            User.is_active = 1
            AND
            BlacklistUser.has_run = 0
        )
    SET
        User.is_active = 0,
        BlacklistUser.has_run = 1;

Raisonnement

Si nous devions nous joindre uniquement aux conditions OU, il faudrait essentiellement vérifier chaque ligne 4 fois pour voir si elle devait se joindre, et potentiellement renvoyer beaucoup plus de lignes. Cependant, en lui donnant plus de conditions, il peut "sauter" beaucoup de lignes si elles ne remplissent pas toutes les conditions lors de la jonction.

Prime

C'est plus lisible. Toutes les conditions sont au même endroit et les lignes à mettre à jour sont au même endroit

Luke Watts
la source
4

Et dans MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
Richard
la source
1
Par prudence, le SET doit venir immédiatement après la définition du jeu d'enregistrements! Je viens d'essayer de trouver un scénario similaire dans une base de données Access, qui avait besoin d'une clause WHERE (il ne l'accepterait pas comme une condition ON valide). O had devait venir en dernier pour éviter les erreurs de syntaxe.
Dodecaphone
4

Le moyen le plus simple consiste à utiliser l'expression de table commune (CTE) introduite dans SQL 2005

with cte as
(select u.assid col1 ,s.assid col2 from ud u inner join sale s on u.id = s.udid)
update cte set col1=col2
Kemal AL GAZZAH
la source
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
Abdullah Yousuf
la source
3

Essayez celui-ci, je pense que cela fonctionnera pour vous

update ud

set ud.assid = sale.assid

from ud 

Inner join sale on ud.id = sale.udid

where sale.udid is not null
HARSHIT RATHORE
la source
2

Pour SQLite, utilisez la propriété RowID pour effectuer la mise à jour:

update Table set column = 'NewValue'
where RowID = 
(select t1.RowID from Table t1
join Table2 t2 on t1.JoinField = t2.JoinField
where t2.SelectValue = 'FooMyBarPlease');
KeithTheBiped
la source
1
Pourriez-vous expliquer cela un peu?
Mohammed Noureldin
1
@MohammedNoureldin Je vais essayer d'expliquer. Le problème est de savoir comment mettre à jour une table avec le résultat d'une requête sur une jointure en utilisant la même table. L'instruction (sous-sélection) agit comme une jointure et renvoie un champ système, RowID, qui est un numéro unique pour chaque ligne d'une table. Étant donné que la sous-sélection peut renvoyer plusieurs lignes, "où RowID =" sélectionne une seule ligne correcte dans la sous-sélection résultante et effectue la mise à jour de la colonne. Faites-moi savoir si vous avez besoin de plus de précisions ou si vous avez besoin de trouver une variation sur ce thème.
KeithTheBiped