2013-08-06 21 views
5

Ho una tabella in MySQL:come MySQL tabella di aggiornamento autonomo lavoro

CREATE TABLE test.tem(a INT,b INT);  

Con seguito di dati:

INSERT INTO test.tem VALUES(1,2),(1,1),(1,NULL),(2,3); 

Ora i dati dovrebbero essere:

+------+------+ 
| a | b | 
+------+------+ 
| 1 | 2 | 
| 1 | 1 | 
| 1 | NULL | 
| 2 | 3 | 
+------+------+ 

voglio aggiornare la colonna b al gruppo min (b) per colonna a.

Così lo SQL dovrebbe essere:

UPDATE test.tem o 
SET o.b = (SELECT 
      MIN(b) 
      FROM test.tem i 
      WHERE i.a = o.a) 

Ma MYSQL Impossibile specificare tabella di destinazione per l'aggiornamento nella clausola FROM

Quindi penso che al di sotto di SQL può risolvere il mio problema con buone prestazioni:

UPDATE test.tem t1 
    JOIN test.tem t2 
    ON t1.a = t2.a 
SET t1.b = t2.b 
WHERE t1.b IS NULL 
    OR t1.b > t2.b; 

Ma il risultato è:

+------+------+ 
| a | b | 
+------+------+ 
| 1 | 1 | 
| 1 | 1 | 
| 1 | 2 | 
| 2 | 3 | 
+------+------+ 

In realtà il risultato quello che serve è:

+------+------+ 
| a | b | 
+------+------+ 
| 1 | 1 | 
| 1 | 1 | 
| 1 | 1 | 
| 2 | 3 | 
+------+------+ 

Domanda 1: Perché MYSQL funzionato il risultato non corretto con l'SQL? Quale dovrebbe essere l'SQL corretto con una buona efficienza?
Domanda 2: quale dovrebbe essere l'SQL se voglio solo aggiornare b con valore NULL (aggiornare solo il terzo record)?

Circa la domanda di 2, ho cercato di usare lo SQL non corretta di seguito:

UPDATE test.tem t1 
    JOIN test.tem t2 
    ON t1.a = t2.a 
    AND t1.b IS NULL 
SET t1.b = t2.b 
WHERE t1.b IS NULL 
    OR t1.b > t2.b; 

risposta

4

Non hai una colonna univoca per identificare le tue righe. Quindi il tuo JOIN probabilmente aggiornerà più righe come credi.


probabilmente si desidera qualcosa di simile, invece:

UPDATE tem AS t1 JOIN (SELECT a, MIN(b) AS m FROM tem GROUP BY a) AS t2 
USING (a) 
SET t1.b = t2.m; 

Vedi http://sqlfiddle.com/#!2/c6a04/1


Se si desidera aggiornare solo le righe che hanno NULL nella colonna b, questo è solo una questione di WHERE clausola:

CREATE TABLE tem(a INT,b INT);  
INSERT INTO tem VALUES(1,2),(1,1),(1,NULL),(2,3); 

UPDATE tem AS t1 JOIN (SELECT a, MIN(b) AS m FROM tem GROUP BY a) AS t2 
USING (a) 
SET t1.b = t2.m 
WHERE t1.b IS NULL; 

Vedi http://sqlfiddle.com/#!2/31ffb/1

+0

ci vogliono circa 5 minuti per aggiornare in una tabella con 4,5 milioni di record utilizzando SQL. Potete aiutarmi a scoprire la colpa del mio SQL? – bluearrow

+0

@bluearrow Poiché questo è un argomento diverso, dovresti fare un'altra domanda, fornendo la struttura della tabella (incluso l'indice), la richiesta e il suo [piano di query] (http://dev.mysql.com/doc/refman /4.1/en/execution-plan-information.html). –

+0

Guarda la tua risposta: http://stackoverflow.com/questions/18117717/mysql-join-update-internal-steps – bluearrow

0

Si potrebbe utilizzare una tabella temporanea per fare questo:

create temporary table tem2 (a INT, b INT); 

insert into tem2 
    select a, min(b) from tem group by a; 

update tem 
    inner join tem2 on tem.a = tem2.a 
    set tem.b = tem2.b; 

drop table tem2; 

penso che dovrebbe funzionare. Il "drop table" non è strettamente necessario poiché tem2 verrà comunque rimosso quando la connessione è chiusa, sebbene sia una buona forma.

0

Write it as a JOIN instead:

UPDATE tem 
JOIN (SELECT a, MIN(b) AS min_b FROM tem GROUP BY a) AS mins USING (a) 
SET tem.b = mins.min_b ; 
+0

Questo è un buon metodo. Ma penso che la tabella dei min non abbia indice. Potete aiutarmi a scoprire la colpa del mio SQL? – bluearrow

Problemi correlati