ACTUALIZAR múltiples tablas en MySQL usando LEFT JOIN


165

Tengo dos tablas y quiero actualizar los campos en T1 para todas las filas de una IZQUIERDA.

Para un ejemplo sencillo, actualice todas las filas del siguiente conjunto de resultados:

SELECT T1.* FROM T1 LEFT JOIN T2 ON T1.id = T2.id WHERE T2.id IS NULL  

El manual de MySQL establece que:

Las instrucciones UPDATE de varias tablas pueden usar cualquier tipo de combinación permitida en las instrucciones SELECT, como LEFT JOIN.

Pero no puedo encontrar la sintaxis adecuada para hacerlo en la ACTUALIZACIÓN de tablas múltiples documentada.

¿Cuál es la sintaxis adecuada?

Respuestas:


318
UPDATE  t1
LEFT JOIN
        t2
ON      t2.id = t1.id
SET     t1.col1 = newvalue
WHERE   t2.id IS NULL

Tenga en cuenta que para un SELECTsería más eficiente usar NOT IN/ NOT EXISTSsintaxis:

SELECT  t1.*
FROM    t1
WHERE   t1.id NOT IN
        (
        SELECT  id
        FROM    t2
        )

Consulte el artículo en mi blog para obtener detalles sobre el rendimiento:

Desafortunadamente, MySQLno permite usar la tabla de destino en una subconsulta en una UPDATEdeclaración, es por eso que deberá atenerse a una LEFT JOINsintaxis menos eficiente .


No funciona en Oracle. Ver esta publicación en ese caso.
Jon Ander

¿Podemos agregar un límite a esto? Como si solo quisiera actualizar 10000 filas a la vez. Si solo agrego LIMIT 10000 me da un error que dice 'Uso incorrecto de ACTUALIZACIÓN y LÍMITE'
Haril Satra

28

Lo mismo se puede aplicar a un escenario donde los datos se han normalizado, pero ahora desea que una tabla tenga valores encontrados en una tercera tabla. Lo siguiente le permitirá actualizar una tabla con información de una tercera tabla que le gusta a una segunda tabla.

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;

Esto sería útil en el caso de que tuviera usuarios y grupos, y quisiera que un usuario pudiera agregar su propia variación del nombre del grupo, por lo que originalmente querría importar los nombres de grupo existentes en el campo donde está el usuario voy a poder modificarlo.


4
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  |

Actualizaré el texto del campo en la tabla A con

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`

y llega a este resultado:

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   |                        |
--------+-------------------------+

donde solo se acepta un campo de la Tabla B, pero llegaré a este resultado:

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   |                                            |
+--------+--------------------------------------------+

0
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`)
)

-1
                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)

3
¡Agregue una explicación para que la respuesta sea más útil!
namezero
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.