2011-11-28 14 views
15

Jak wstawić wybrane wiersze z table_source do table_target za pomocą SQL w MySQL gdzie:INSERT INTO ... SELECT bez wyszczególnieniem wszystkich kolumn

  • obie tabele mają ten sam schemat
  • Wszystkie kolumny należy przenieść z wyjątkiem auto-przyrost id
  • bez wyraźnego piśmie wszystkie nazwy kolumn, jak to byłoby uciążliwe

trywialne INSERT INTO table_target SELECT * FROM table_source kończy się niepowodzeniem przy duplikowaniu wpisów dla klucza podstawowego.

Odpowiedz

11

Albo listę wszystkich pól, które mają we wkładce ... select, lub użyć coś innego na zewnątrz, aby zbudować dla ciebie listę.

SQL nie ma czegoś takiego jak SELECT * except somefield FROM, więc będziesz musiał ugryźć bullet i wypisać nazwy pól.

+2

Jesteś dobrze, w końcu użyłem wyraźnej składni. Dla kompletności: łatwo uzyskaj listę kolumn za pomocą ['DESCRIBE'] (http://dev.mysql.com/doc/refman/5.0/en/describe.html), a następnie użyj składni' INSERT INTO table1 (field1, field2 , field3) SELECT table2.field1, table2.field2, table2.field3 FROM table2; ' – Jonathan

+0

Najprostszym sposobem uzyskania nazw pól CSV: ' SELECT CONCAT (GROUP_CONCAT (SEPARATOR KOLUMNOWY ','), "\ n") FROM INFORMATION_SCHEMA .COLUMNS WHERE TABLE_SCHEMA = 'dbname' I TABLE_NAME = 'tablename' GROUP BY TABLE_NAME' – Hafenkranich

2

Oczywiście klucz podstawowy musi być unikalny. To zależy od tego, co chcesz osiągnąć, ale możesz wykluczyć wiersze z kluczem podstawowym, który już istnieje.

INSERT INTO table_target SELECT * FROM table_source 
WHERE table_source.id NOT IN (SELECT id FROM table_target) 

UPDATE: ponieważ trzeba także dodatkowe wiersze, należy najpierw rozwiązać konflikt, czy table_source mają relacje? Jeśli nie, możesz zmienić te klucze:

UPDATE table_source SET id = id + 1000 
WHERE id IN (SELECT id FROM table_target) 

Gdzie 1000, jest stałe, wystarczająco duże, aby można je było po zakończeniu stołu.

+0

muszę te wiersze zbyt ... – Jonathan

+0

ok, zaktualizowane odpowiedź – stivlo

+0

że to dobry obejście tylko wtedy, gdy nie masz kluczy obcych, wskazując na 'table_source'. Ponadto, jeśli istnieje sposób na dynamiczne pobranie największego id w 'table_target' zamiast użycia stałej, byłoby to nieco lepsze obejście. – Jonathan

15

Nazwy kolumn muszą być określone -

INSERT INTO table_target SELECT NULL, column_name1, column_name2, column_name3, ... 
    FROM table_source; 

Wystarczy przekazać NULL jako wartość dla pola id automatycznego.

+0

Dzięki! To pomogło. – Hafenkranich

0

INSERT IGNORE po prostu "ominąć" duplikaty wierszy.

http://dev.mysql.com/doc/refman/5.5/en/insert.html

+0

Czy to nie byłoby ... okropne ?! – Jonathan

+0

Nie, jeśli ignorowane wiersze są potrzebnymi wierszami. w przeciwnym razie możesz usunąć według ID (lub innego unikalnego pola) i "INSERT". –

3

Tedious ale bezpieczne i prawidłowe.

Pisanie instrukcji INSERT bez podania listy kolumn prowadzi do kodu trudnego do debugowania i, co ważniejsze, bardzo delikatnego kodu, który zostanie złamany, jeśli definicja tabeli zostanie zmieniona.

Jeśli absolutnie nie możesz wpisać nazw kolumn samemu, to stosunkowo łatwo jest zbudować narzędzie do kodu, które utworzy dla ciebie listę rozdzielaną przecinkami.

0

Prawdopodobnie można to zrobić za pomocą przygotowanych wyciągów.

PREPARE table_target_insert FROM 'INSERT INTO table_target SELECT ? FROM table_source'; 
SET @cols:=''; 
SELECT @cols:=GROUP_CONCAT(IF(column_name = 'id','NULL',column_name) separator ",") FROM information_schema.columns WHERE table_name='table_source'; 
EXECUTE table_target_insert USING @cols; 
0

Wygląda na to, że kolumny nie mogą być podane jako właściciel miejsca w Przygotowanej instrukcji MySQL. Mam skompilowane następujące rozwiązanie do testowania:

SET @schema_db = 'DB'; 
SET @table = 'table'; 
SET @cols = (SELECT CONCAT(GROUP_CONCAT(COLUMN_NAME SEPARATOR ', '), "\n") FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema_db AND TABLE_NAME = @table GROUP BY TABLE_NAME); 
SET @Querystr = CONCAT('SELECT',' ', @cols,' ','FROM',' ',@schema_db,'.',@table,' ', 'Limit 5'); 
PREPARE stmt FROM @Querystr; 
EXECUTE stmt; 
1

To moje ostateczne rozwiązanie do masowej aktualizacji za pomocą polecenia „Wstaw” zastąpić.

SET @@session.group_concat_max_len = @@global.max_allowed_packet; 
SET @schema_db = 'db'; 
SET @tabl = 'table'; 
SET @cols = (SELECT CONCAT('`',GROUP_CONCAT(COLUMN_NAME SEPARATOR '`, `'), '`') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema_db AND TABLE_NAME = @tabl GROUP BY TABLE_NAME); 
SET @Querystr = CONCAT('REPLACE INTO ',@schema_db,'.',@tabl,' SELECT ', @cols,' FROM import.tbl_', @tabl); 

PREPARE stmt FROM @Querystr; 
EXECUTE stmt;