UPDATE plusieurs tables dans MySQL en utilisant LEFT JOIN
-
03-07-2019 - |
Question
J'ai deux tables et je souhaite mettre à jour les champs dans T1 pour toutes les lignes d'un LEFT JOIN.
Pour un exemple simple, mettez à jour toutes les lignes de l'ensemble de résultats suivant:
SELECT T1.* FROM T1 LEFT JOIN T2 ON T1.id = T2.id WHERE T2.id IS NULL
Le manuel MySQL indique que:
Les instructions UPDATE à tables multiples peuvent utiliser tout type de jointure autorisée dans les instructions SELECT, telle que LEFT JOIN.
Mais je ne trouve pas la syntaxe appropriée pour cela dans la documentation UPDATE à tables multiples documentée.
Quelle est la syntaxe appropriée?
La solution
UPDATE t1
LEFT JOIN
t2
ON t2.id = t1.id
SET t1.col1 = newvalue
WHERE t2.id IS NULL
Notez que pour un SELECT
, il serait plus efficace d'utiliser la syntaxe NOT IN
/ NOT EXISTS
:
SELECT t1.*
FROM t1
WHERE t1.id NOT IN
(
SELECT id
FROM t2
)
Voir l'article de mon blog pour plus de détails sur les performances:
- Recherche de commandes incomplètes : performances de
LEFT JOIN
par rapport àNOT IN
Malheureusement, MySQL
n'autorise pas l'utilisation de la table cible dans une sous-requête dans une instruction UPDATE
, vous devez donc vous en tenir à des solutions moins efficaces LEFT JOIN
syntaxe.
Autres conseils
La même chose peut être appliquée à un scénario où les données ont été normalisées, mais maintenant vous voulez que les valeurs d'une table soient trouvées dans une troisième table. Ce qui suit vous permettra de mettre à jour une table avec les informations d'une troisième table qui est appréciée par une deuxième table.
UPDATE t1
LEFT JOIN
t2
ON
t2.some_id = t1.some_id
LEFT JOIN
t3
ON
t2.t3_id = t3.id
SET
t1.new_column = t3.column;
Cela serait utile dans le cas où vous auriez des utilisateurs et des groupes et que vous souhaitiez qu'un utilisateur puisse ajouter sa propre variante du nom du groupe. Par conséquent, vous voudriez à l'origine importer les noms de groupes existants dans le champ où l'utilisateur va pouvoir le modifier.
Table A
+--------+-----------+
| A-num | text |
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
+--------+-----------+
Table B
+------+------+--------------+
| B-num| date | A-num |
| 22 | 01.08.2003 | 2 |
| 23 | 02.08.2003 | 2 |
| 24 | 03.08.2003 | 1 |
| 25 | 04.08.2003 | 4 |
| 26 | 05.03.2003 | 4 |
Je mettrai à jour le texte du champ dans le tableau A avec
UPDATE `Table A`,`Table B`
SET `Table A`.`text`=concat_ws('',`Table A`.`text`,`Table B`.`B-num`," from
",`Table B`.`date`,'/')
WHERE `Table A`.`A-num` = `Table B`.`A-num`
et arriver à ce résultat:
Table A
+--------+------------------------+
| A-num | text |
| 1 | 24 from 03 08 2003 / |
| 2 | 22 from 01 08 2003 / |
| 3 | |
| 4 | 25 from 04 08 2003 / |
| 5 | |
--------+-------------------------+
où un seul champ de la table B est accepté, mais je vais arriver à ce résultat:
Table A
+--------+--------------------------------------------+
| A-num | text |
| 1 | 24 from 03 08 2003 |
| 2 | 22 from 01 08 2003 / 23 from 02 08 2003 / |
| 3 | |
| 4 | 25 from 04 08 2003 / 26 from 05 03 2003 / |
| 5 | |
+--------+--------------------------------------------+
UPDATE `Table A` a
SET a.`text`=(
SELECT group_concat(b.`B-num`,' from ',b.`date` SEPARATOR ' / ')
FROM `Table B` b WHERE (a.`A-num`=b.`A-num`)
)
DECLARE @cols VARCHAR(max),@colsUpd VARCHAR(max), @query VARCHAR(max),@queryUpd VARCHAR(max), @subQuery VARCHAR(max)
DECLARE @TableNameTest NVARCHAR(150)
SET @TableNameTest = @TableName+ '_Staging';
SELECT @colsUpd = STUF ((SELECT DISTINCT '], T1.[' + name,']=T2.['+name+'' FROM sys.columns
WHERE object_id = (
SELECT top 1 object_id
FROM sys.objects
WHERE name = ''+@TableNameTest+''
)
and name not in ('Action','Record_ID')
FOR XML PATH('')
), 1, 2, ''
) + ']'
Select @queryUpd ='Update T1
SET '+@colsUpd+'
FROM '+@TableName+' T1
INNER JOIN '+@TableNameTest+' T2
ON T1.Record_ID = T2.Record_Id
WHERE T2.[Action] = ''Modify'''
EXEC (@queryUpd)