2013-08-06 16 views
5

Mam tabeli w MySQL:jak mysql tabela zmiana samo dzieło

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

Z poniżej dane:

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

Teraz dane powinny być:

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

chcę zaktualizuj kolumnę b do grupy min (b) według kolumny a.

Więc SQL powinny być:

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

Ale MYSQL Nie można określić tabelę docelową dla aktualizacji w klauzuli FROM

Więc myślę, poniżej SQL może rozwiązać moje pytanie z dobrymi wynikami:

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; 

ale wynik jest:

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

Właściwie wynikiem czego potrzebuję to:

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

Pytanie 1: Dlaczego MySQL wypracować nieprawidłowy wynik z SQL? Jak powinien wyglądać poprawny SQL z dobrą wydajnością?
Pytanie 2: Jaki powinien być kod SQL, jeśli chcę tylko zaktualizować b wartością NULL (aktualizować tylko trzeci rekord)?

O pytaniu 2, próbowałem użyć nieprawidłowy SQL poniżej:

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; 

Odpowiedz

4

Nie masz unikalnej kolumny, która identyfikuje twoje wiersze. Tak więc Twój JOIN prawdopodobnie zaktualizuje więcej wierszy, jak myślisz.


Prawdopodobnie chcesz coś takiego zamiast:

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; 

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


Jeśli chcesz tylko zaktualizować wiersze o NULL w kolumnie b, to tylko kwestia z klauzuli WHERE:

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; 

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

+0

To trwa około 5 minut, aby zaktualizować w jednej tabeli z 4,5 milionów płyt wykorzystujących swój SQL. Czy możesz mi pomóc w znalezieniu błędu mojego SQL? – bluearrow

+0

@bluearrow Ponieważ jest to inny temat, powinieneś zadać inne pytanie, podając strukturę tabeli (włącznie z indeksem), prośbę i jej [plan kwerend] (http://dev.mysql.com/doc/refman /4.1/en/execution-plan-information.html). –

+0

Sprawdź swoją odpowiedź: http://stackoverflow.com/questions/18117717/mysql-join-update-internal-steps – bluearrow

0

Można użyć tabeli tymczasowej, aby to zrobić:

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; 

myślę, że powinno działać. "Tabela kropel" nie jest bezwzględnie konieczna, ponieważ tem2 zostanie zerwane, mimo że połączenie zostanie zamknięte, mimo że jest to dobra 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

To dobra metoda. Ale myślę, że tabela mins nie ma indeksu. Czy możesz mi pomóc w znalezieniu błędu mojego SQL? – bluearrow