MySQL: consulta de ACTUALIZACIÓN basada en la consulta SELECT

501

Necesito verificar (de la misma tabla) si hay una asociación entre dos eventos en función de la fecha y la hora.

Un conjunto de datos contendrá la fecha y hora de finalización de ciertos eventos y el otro conjunto de datos contendrá la fecha y hora de inicio para otros eventos.

Si el primer evento se completa antes del segundo evento, me gustaría vincularlos.

Lo que tengo hasta ahora es:

SELECT name as name_A, date-time as end_DTS, id as id_A 
FROM tableA WHERE criteria = 1


SELECT name as name_B, date-time as start_DTS, id as id_B 
FROM tableA WHERE criteria = 2

Entonces me uno a ellos:

SELECT name_A, name_B, id_A, id_B, 
if(start_DTS > end_DTS,'VALID','') as validation_check
FROM tableA
LEFT JOIN tableB ON name_A = name_B

¿Puedo entonces, en función de mi campo validation_check, ejecutar una consulta UPDATE con SELECT anidado?

John M
fuente
2
¿No estoy seguro de lo que estás preguntando? ¿Estás tratando de descubrir cómo hacer una actualización con un SQL Select?
RiddlerDev

Respuestas:

812

En realidad, puede hacer esto de dos maneras:

Actualización de MySQL sintaxis de unión:

UPDATE tableA a
INNER JOIN tableB b ON a.name_a = b.name_b
SET validation_check = if(start_dts > end_dts, 'VALID', '')
-- where clause can go here

Sintaxis ANSI SQL:

UPDATE tableA SET validation_check = 
    (SELECT if(start_DTS > end_DTS, 'VALID', '') AS validation_check
        FROM tableA
        INNER JOIN tableB ON name_A = name_B
        WHERE id_A = tableA.id_A)

Elija el que le parezca más natural.

Eric
fuente
92
La primera forma (actualizar con join) será mucho más eficiente que la segunda. El primero haría una sola combinación, mientras que el segundo ejecutaría la consulta de selección para cada fila de la tabla A.
ColinM
16
Para el primer ejemplo, ¿no deberías usar una unión interna? ¿La combinación de la izquierda no dará como resultado que validation_check se establezca en nulo para los registros de la tabla A sin un registro correspondiente de la tabla B?
Cerin
3
@Cerin sí, eso me pasó a mí. ¡Debería ser una unión interna! O simplemente déjalo como unirse. Si no tiene una unión interna, la unión izquierda significa que todos los registros de la tabla A se actualizarán. ¡Esto es muy peligroso!
CMCDragonkai
10
Gracias por el primero (y). Si bien esta respuesta tiene más de 7 años. No puedo creer por qué nadie ha declarado que el segundo no funciona en alguna base de datos como MySQL. Obtendrá este error:You can't specify target table ___ for update in FROM clause SQL.sql
Jugali Lakota
1
Además, tenga en cuenta que hasta hace poco, el primer enfoque no funcionaba con MySQL cuando tableA= tableB. Estás obligado a crear una tabla temporal para almacenar el resultado intermedio. (tuvo que escribir una consulta similar para un script de migración)
svvac
301
UPDATE
    `table1` AS `dest`,
    (
        SELECT
            *
        FROM
            `table2`
        WHERE
            `id` = x
    ) AS `src`
SET
    `dest`.`col1` = `src`.`col1`
WHERE
    `dest`.`id` = x
;

Espero que esto funcione para usted.

cita masiva
fuente
55
Esta es, con mucho, la consulta más rápida. Editar: al tener dest con 22K filas y src con 4K filas, tardó menos de 1 segundo en completarse, mientras que la respuesta superior superó 60 segundos.
Chris Dev
1
Sí, esta es la consulta más rápida, por cierto, también puede agregar la cláusula WHERE
robinmag
1
más rápido no siempre implica que sea bueno, esta actualización no funcionará en todos los casos, de hecho, en algunos casos tendrá un comportamiento inesperado, todo esto es por qué no poner una condición y eso no es una unión
Emiliano
114

Fácil en MySQL:

UPDATE users AS U1, users AS U2 
SET U1.name_one = U2.name_colX
WHERE U2.user_id = U1.user_id
Sergio
fuente
58

Si alguien busca actualizar datos de una base de datos a otra sin importar a qué tabla se dirija, debe haber algunos criterios para hacerlo.

Este es mejor y limpio para todos los niveles:

UPDATE dbname1.content targetTable

LEFT JOIN dbname2.someothertable sourceTable ON
    targetTable.compare_field= sourceTable.compare_field
SET
    targetTable.col1  = sourceTable.cola,
    targetTable.col2 = sourceTable.colb, 
    targetTable.col3 = sourceTable.colc, 
    targetTable.col4 = sourceTable.cold 

Traaa! ¡Funciona muy bien!

Con la comprensión anterior, puede modificar los campos establecidos y los criterios "on" para hacer su trabajo. También puede realizar las comprobaciones, luego extraer los datos en las tablas temporales y luego ejecutar la actualización utilizando la sintaxis anterior reemplazando los nombres de las tablas y columnas.

Espero que funcione, si no, házmelo saber. Escribiré una consulta exacta para usted.

KMX
fuente
24
UPDATE 
  receipt_invoices dest,
  (
    SELECT 
      `receipt_id`,
      CAST((net * 100) / 112 AS DECIMAL (11, 2)) witoutvat 
    FROM
      receipt 
    WHERE CAST((net * 100) / 112 AS DECIMAL (11, 2)) != total 
      AND vat_percentage = 12
  ) src 
SET
  dest.price = src.witoutvat,
  dest.amount = src.witoutvat 
WHERE col_tobefixed = 1 
  AND dest.`receipt_id` = src.receipt_id ;

Espero que esto te ayude en un caso en el que tengas que combinar y actualizar entre dos tablas.

Don
fuente
12

Encontré esta pregunta al buscar mi propia solución para una combinación muy compleja. Esta es una solución alternativa, a una versión más compleja del problema, que pensé que podría ser útil.

Necesitaba rellenar el campo product_id en la tabla de actividades, donde las actividades están numeradas en una unidad y las unidades están numeradas en un nivel (identificado mediante una cadena ?? N), de modo que uno pueda identificar actividades utilizando una SKU, es decir, L1U1A1. Esos SKU se almacenan en una tabla diferente.

Identifiqué lo siguiente para obtener una lista de activity_id vs product_id: -

SELECT a.activity_id, w.product_id 
  FROM activities a 
  JOIN units USING(unit_id) 
  JOIN product_types USING(product_type_id) 
  JOIN web_products w 
    ON sku=CONCAT('L',SUBSTR(product_type_code,3), 'U',unit_index, 'A',activity_index)

Descubrí que eso era demasiado complejo para incorporarlo a un SELECT dentro de mysql, así que creé una tabla temporal y la uní con la declaración de actualización:

CREATE TEMPORARY TABLE activity_product_ids AS (<the above select statement>);

UPDATE activities a
  JOIN activity_product_ids b
    ON a.activity_id=b.activity_id 
  SET a.product_id=b.product_id;

Espero que alguien encuentre esto útil

sibaz
fuente
dos consultas pueden no dar un resultado consistente en un entorno de subprocesos múltiples.
Donald
7
UPDATE [table_name] AS T1,
      (SELECT [column_name] 
        FROM [table_name] 
        WHERE [column_name] = [value]) AS T2 
  SET T1.[column_name]=T2.[column_name] + 1
WHERE T1.[column_name] = [value];
bhavik
fuente
4

Puede actualizar valores de otra tabla usando la unión interna como esta

UPDATE [table1_name] AS t1 INNER JOIN [table2_name] AS t2 ON t1.column1_name] = t2.[column1_name] SET t1.[column2_name] = t2.column2_name];

Siga aquí para saber cómo utilizar esta consulta http://www.voidtricks.com/mysql-inner-join-update/

o puede usar select como subconsulta para hacer esto

UPDATE [table_name] SET [column_name] = (SELECT [column_name] FROM [table_name] WHERE [column_name] = [value]) WHERE [column_name] = [value];

consulta explicada en detalles aquí http://www.voidtricks.com/mysql-update-from-select/

Anand Roshan
fuente
4

Puedes usar:

UPDATE Station AS st1, StationOld AS st2
   SET st1.already_used = 1
 WHERE st1.code = st2.code
SergeyUr
fuente
3

Para la misma mesa,

UPDATE PHA_BILL_SEGMENT AS PHA,
     (SELECT BILL_ID, COUNT(REGISTRATION_NUMBER) AS REG 
       FROM PHA_BILL_SEGMENT
        GROUP BY REGISTRATION_NUMBER, BILL_DATE, BILL_AMOUNT
        HAVING REG > 1) T
    SET PHA.BILL_DATE = PHA.BILL_DATE + 2
 WHERE PHA.BILL_ID = T.BILL_ID;
Gnanam pragasam
fuente
1

Tuve un problema con las entradas duplicadas en una misma tabla. A continuación se muestran los enfoques que estaban funcionando para mí. También ha sido defendido por @sibaz.

Finalmente lo resolví usando las siguientes consultas:

  1. La consulta de selección se guarda en una tabla temporal

    IF OBJECT_ID(N'tempdb..#New_format_donor_temp', N'U') IS NOT NULL
        DROP TABLE #New_format_donor_temp;
    
    select *
    into #New_format_donor_temp
    from DONOR_EMPLOYMENTS
    where DONOR_ID IN (
      1, 2
    )
    
    -- Test New_format_donor_temp
    -- SELECT *
    -- FROM #New_format_donor_temp;
  2. La tabla temporal se une en la consulta de actualización.

    UPDATE de
    SET STATUS_CD=de_new.STATUS_CD, STATUS_REASON_CD=de_new.STATUS_REASON_CD, TYPE_CD=de_new.TYPE_CD
    FROM DONOR_EMPLOYMENTS AS de
      INNER JOIN #New_format_donor_temp AS de_new ON de_new.EMP_NO = de.EMP_NO
    WHERE
      de.DONOR_ID IN (
        3, 4
    )

No tengo mucha experiencia con SQL, por favor aconseje cualquier enfoque mejor que conozca.

Las consultas anteriores son para el servidor MySql.

Almiar
fuente