¿Cómo puedo hacer una instrucción UPDATE con JOIN en SQL Server?

1314

Necesito actualizar esta tabla en SQL Server con datos de su tabla 'padre', ver a continuación:

Mesa: venta

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

Tabla: ud

id  (int)
assid  (int)

sale.assidcontiene el valor correcto para actualizar ud.assid.

¿Qué consulta hará esto? Estoy pensando en un joinpero no estoy seguro de si es posible.

Ant Swift
fuente
3
¿Qué RDBMS estás usando? MySQL, SQL Server, Oracle, PostgreSQL o algo más?
Chris J
algunas relaciones entre las mesas? ¿Cómo se puede saber qué registro de venta corresponde a qué registro de ud? ¿Se basa en la identificación como clave principal en ambas tablas?
Cătălin Pitiș
¿Cómo puedes actualizar UD? Solo tiene el assid y su propia identificación. ¿Podría dar un ejemplo en términos de los valores reales que existen y los registros que le gustaría cambiar o agregar como resultado del script?
Bernhard Hofmann
2
Vea también la pregunta SO ... stackoverflow.com/questions/982919/sql-update-query-using-joins
SteveC
2
Alias ​​de usuario en consulta como stackoverflow.com/questions/982919/sql-update-query-using-joins
Imran Muhammad

Respuestas:

2383

La sintaxis depende estrictamente de qué DBMS de SQL esté utilizando. Aquí hay algunas formas de hacerlo en ANSI / ISO (también conocido como debería funcionar en cualquier SQL DBMS), MySQL, SQL Server y Oracle. Tenga en cuenta que mi método ANSI / ISO sugerido generalmente será mucho más lento que los otros dos métodos, pero si está utilizando un DBMS SQL que no sea MySQL, SQL Server u Oracle, entonces puede ser el único camino a seguir (por ejemplo, si su SQL DBMS no es compatible 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

Servidor 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;

Tenga en cuenta que la tabla de destino no debe repetirse en la FROMcláusula de Postgres.

Oráculo:

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
fuente
3
Me parece que set assid = s.assiddebería ser MySQL set u.assid = s.assid.
dotancohen
2
En la sintaxis ANSI, ¿qué sucede si SELECT después de =devuelve más de una fila?
Deseche la cuenta
2
@ ThrowawayAccount3Million Probablemente fallará. AFAIK, este tipo de operación esperaría un valor escalar y arrojará un error si se le da un conjunto de resultados.
Francis Lord
66
¡Deseo que el OP elija algunos mejores nombres para su tabla y columnas! no es tan legible / intuitivo ...
S.Serpooshan
44
Postgre 9.3 funcionó solo conupdate ud set assid = s.assid
StackUnder
143

Esto debería funcionar en SQL Server:

update ud 
set assid = sale.assid
from sale
where sale.udid = id
edosoft
fuente
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 
usuario1154043
fuente
20
La respuesta sería más útil si utilizara los nombres de tabla / columna utilizados en la pregunta. ¿Por qué hay 3 tablas en tu respuesta?
alfonx
50

Un enfoque estándar de SQL sería

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

En SQL Server puede usar una unión

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id
MattH
fuente
1
Con la primera, no puedes igualar en más de 2 columnas, pero unirse funciona muy bien.
makciook
66
@makciook: ¿eh? Puede agregar más condiciones en la WHEREcláusula si desea hacer coincidir columnas adicionales.
siride
2
Solo un poco ... pero creo que el OP significaba sale.udid = ud.id. Y no 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
fuente
26

Consulta de actualización simplificada utilizando JOIN -ing múltiples tablas.

   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

Nota : first_table, second_table, third_table y some_column como 123456 son nombres de tablas de demostración, nombres de columnas e identificadores. Reemplácelos con los nombres válidos.

Vinit Kadkol
fuente
16

Otro ejemplo de por qué SQL no es realmente portátil.

Para MySQL sería:

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

Para obtener más información, lea la actualización de varias tablas: 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
fuente
2
¡+1 en el comentario "por qué SQL no es realmente portátil"! La portabilidad es tan frágil que solo declarar una variable romperá la portabilidad entre muchos de los motores de bases de datos populares.
Jeff Moden
8

Teradata Aster ofrece otra forma interesante de cómo lograr el objetivo:

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
fuente
8

Estaba pensando que el SQL-Server en la publicación superior funcionaría para Sybase ya que ambos son T-SQL, pero desafortunadamente no.

Para Sybase encontré que la actualización debe estar en la tabla en sí, no en el alias:

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

La siguiente declaración con la palabra clave FROM se usa para actualizar varias filas con una unión

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

MySQL

Obtendrá el mejor rendimiento si olvida la cláusula where y coloca todas las condiciones en la expresión ON.

Creo que esto se debe a que la consulta primero debe unir las tablas y luego ejecuta la cláusula where sobre eso, por lo que si puede reducir lo que se requiere para unirse, esa es la forma más rápida de obtener los resultados / hacer la udpate.

Ejemplo

Guión

Tienes una tabla de usuarios. Pueden iniciar sesión con su nombre de usuario o correo electrónico o número de cuenta. Estas cuentas pueden estar activas (1) o inactivas (0). Esta tabla tiene 50000 filas.

Luego tiene una tabla de usuarios para deshabilitar de una vez porque descubre que todos han hecho algo malo. Sin embargo, esta tabla tiene una columna con nombres de usuario, correos electrónicos y números de cuenta combinados. También tiene un indicador "has_run" que debe establecerse en 1 (verdadero) cuando se ha ejecutado

Consulta

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;

Razonamiento

Si tuviéramos que unirnos solo en las condiciones OR, esencialmente necesitaría verificar cada fila 4 veces para ver si debería unirse, y potencialmente devolver muchas más filas. Sin embargo, al darle más condiciones, puede "omitir" muchas filas si no cumplen todas las condiciones al unirse.

Prima

Es más legible. Todas las condiciones están en un solo lugar y las filas para actualizar están en un solo lugar

Luke Watts
fuente
4

Y en MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
Ricardo
fuente
1
Como advertencia, ¡el SET debe aparecer inmediatamente después de la definición del conjunto de registros! Acabo de intentar resolver un escenario similar en una base de datos de Access, que necesitaba una cláusula WHERE (no lo aceptaría como una condición ON válida). DÓNDE tenía que venir el último para evitar errores de sintaxis.
Dodecaphone
4

La forma más sencilla es utilizar la expresión de tabla común (CTE) introducida en 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
fuente
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
Abdullah Yousuf
fuente
3

Prueba este, creo que esto funcionará para ti

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
fuente
2

Para SQLite, use la propiedad RowID para realizar la actualización:

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
fuente
1
¿Podría explicar esto un poco?
Mohammed Noureldin
1
@MohammedNoureldin Trataré de explicarlo. El problema es cómo actualizar una tabla con un resultado de una consulta en unir usando la misma tabla. La instrucción (sub-selección) actúa como una unión y devuelve un campo del sistema, RowID, que es un número único para cada fila de una tabla. Como la sub-selección puede devolver varias filas, "donde RowID =" selecciona una sola fila correcta de la sub-selección resultante y realiza la actualización a la columna. Avíseme si necesita más aclaraciones o si necesita descubrir una variación sobre este tema.
KeithTheBiped