MySQL: query UPDATE basata su SELECT Query


501

Devo verificare (dalla stessa tabella) se esiste un'associazione tra due eventi in base alla data-ora.

Una serie di dati conterrà la data-ora di fine di determinati eventi e l'altra serie di dati conterrà la data-ora di inizio per altri eventi.

Se il primo evento viene completato prima del secondo evento, vorrei collegarli.

Quello che ho finora è:

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

Quindi mi unisco a loro:

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

Posso quindi, in base al mio campo validation_check, eseguire una query UPDATE con SELECT nidificato?


2
Non sono sicuro di quello che stai chiedendo? Stai cercando di capire come eseguire un aggiornamento con SQL Select?
RiddlerDev,

Risposte:


811

Puoi effettivamente farlo in due modi:

Sintassi del join di aggiornamento di MySQL:

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

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

Scegli quello che ti sembra più naturale.


92
Il primo modulo (aggiornamento con join) sarà molto più efficiente del secondo. Il primo farebbe un singolo join, mentre il secondo eseguirà la query di selezione per ogni riga della tabellaA.
ColinM,

16
Per il primo esempio, non dovresti usare un join interno? Il join sinistro non determinerà l'impostazione validation_check su null per i record tableA senza un corrispondente record tableB?
Cerin,

3
@Cerin sì che mi è successo. Dovrebbe essere unirsi interiore! O lascialo come join. Se non hai un join interno, il join sinistro significa che tutti i record della tabella A verranno aggiornati! Questo è molto pericoloso!
CMCDragonkai

10
Grazie per il primo (y). Mentre questa risposta ha più di 7 anni. Non riesco a credere perché nessuno abbia affermato che il secondo non funziona in alcuni database come MySQL. Otterrai questo errore:You can't specify target table ___ for update in FROM clause SQL.sql
Jugali Lakota

1
Inoltre, tieni presente che fino a poco tempo fa, il primo approccio non funzionava con MySQL quando tableA= tableB. Sei costretto a creare una tabella temporanea per memorizzare il risultato intermedio. (ha dovuto scrivere una query simile per uno script di migrazione)
svvac,

301
UPDATE
    `table1` AS `dest`,
    (
        SELECT
            *
        FROM
            `table2`
        WHERE
            `id` = x
    ) AS `src`
SET
    `dest`.`col1` = `src`.`col1`
WHERE
    `dest`.`id` = x
;

Spero che questo funzioni per te.


5
Questa è di gran lunga la query più veloce. Modifica: avendo dest con 22K righe e src con 4K righe, ci sono voluti meno di 1 secondo per il completamento, mentre la risposta superiore ha superato 60 secondi.
Chris Dev,

1
Sì, questa è la query più veloce, a proposito puoi aggiungere anche la clausola WHERE
robinmag,

1
il più veloce non implica sempre bene, questo aggiornamento non funzionerà in tutti i casi, infatti in alcuni casi avrai un comportamento inaspettato, tutto questo è il motivo per cui non mettere una condizione e che non è un join
Emiliano

114

Facile in MySQL:

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

58

Se qualcuno sta cercando di aggiornare i dati da un database a un altro, indipendentemente dalla tabella di destinazione, devono esserci alcuni criteri per farlo.

Questo è migliore e pulito per tutti i livelli:

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! Funziona benissimo!

Con la comprensione di cui sopra, è possibile modificare i campi impostati e i criteri "on" per svolgere il proprio lavoro. È inoltre possibile eseguire i controlli, quindi estrarre i dati nelle tabelle temporanee e quindi eseguire l'aggiornamento utilizzando la sintassi sopra sostituendo i nomi delle tabelle e delle colonne.

Spero che funzioni, se non fammi sapere. Scriverò una domanda esatta per te.


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 ;

Spero che questo ti aiuti in un caso in cui devi abbinare e aggiornare tra due tabelle.


12

Ho trovato questa domanda nel cercare la mia soluzione per un join molto complesso. Questa è una soluzione alternativa a una versione più complessa del problema, che pensavo potesse essere utile.

Avevo bisogno di popolare il campo product_id nella tabella delle attività, in cui le attività sono numerate in un'unità e le unità sono numerate in un livello (identificato utilizzando una stringa ?? N), in modo tale da poter identificare le attività utilizzando uno SKU, ad esempio L1U1A1. Tali SKU vengono quindi archiviati in una tabella diversa.

Ho identificato quanto segue per ottenere un elenco di 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)

Ho scoperto che era troppo complesso per essere incorporato in un SELECT all'interno di mysql, quindi ho creato una tabella temporanea e l'ho unito alla dichiarazione di aggiornamento: -

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;

Spero che qualcuno lo trovi utile


due query potrebbero non dare risultati coerenti in ambienti multi thread.
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];

4

Puoi aggiornare i valori da un'altra tabella usando il join interno in questo modo

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

Segui qui per sapere come utilizzare questa query http://www.voidtricks.com/mysql-inner-join-update/

oppure puoi usare seleziona come sottoquery per fare questo

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

query spiegata in dettaglio qui http://www.voidtricks.com/mysql-update-from-select/


4

Puoi usare:

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

3

Per lo stesso tavolo,

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;

1

Ho avuto un problema con le voci duplicate in una stessa tabella. Di seguito sono riportati gli approcci che funzionavano per me. È stato anche sostenuto da @sibaz.

Alla fine l'ho risolto usando le seguenti domande:

  1. La query di selezione viene salvata in una tabella temporanea

    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 tabella temporanea si unisce alla query di aggiornamento.

    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
    )

Non ho molta esperienza con SQL, per favore, consigli qualsiasi approccio migliore che conosci.

Le query sopra sono per server MySql.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.