Jak skopiować wiersz i wstawić do tej samej tabeli z polem autoinkrementacji w MySQL?


233

W MySQL próbuję skopiować wiersz z autoinkrementacją column ID=1 i wstawić dane do tej samej tabeli, co nowy wiersz column ID=2.

Jak mogę to zrobić w jednym zapytaniu?

Odpowiedzi:


351

Użyj INSERT ... SELECT:

insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where id = 1

gdzie c1, c2, ...są wszystkie kolumny oprócz id. Jeśli chcesz jawnie wstawić z id2, umieść to na liście kolumn WSTAW i wybierz:

insert into your_table (id, c1, c2, ...)
select 2, c1, c2, ...
from your_table
where id = 1

Oczywiście idw drugim przypadku musisz zająć się możliwym duplikatem 2.


1
Mógłbyś programowo uzyskać nazwy kolumn za pomocą INFORMACJE_SCHEMA ... Zastanawiam się, czy mógłbyś to zrobić jako zapytanie podrzędne i jakieś funkcje łańcuchowe? Hmmm ...
Yzmir Ramirez

1
@Yzmir: W końcu musiałbyś używać dynamicznego SQL, co zwykle wymagałoby zbudowania procedury składowanej. Wydaje się, że to więcej kłopotów niż jest warte, kiedy powinieneś mieć pod ręką listę nazw kolumn.
mu jest za krótki

6
Uzgodnione ... z mojego doświadczenia, że ​​po przejściu do procedury składowanej nie wracasz - jesteś teraz żonaty z tą bazą danych i po prostu dodajesz do kosztów, ilekroć chcesz zmienić.
Yzmir Ramirez

11
@YzmirRamirez, sprawiasz, że to brzmi jak małżeństwo z natury złe. :)
Prof. Falken

1
Jak dodać jedną niestandardową wartość w kolumnie ze wszystkimi innymi skopiowanymi polami?
Manish Kumar

49

IMO, najlepiej wydaje się używać instrukcji sql tylko do kopiowania tego wiersza, a jednocześnie tylko do odwoływania się do kolumn, które musisz i chcesz zmienić.

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY

SELECT * FROM your_table WHERE id=1;
UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;
DROP TABLE temp_table;

Zobacz także av8n.com - jak sklonować rekord SQL

Korzyści:

  • Instrukcje SQL 2 wspominają tylko o polach, które należy zmienić podczas procesu klonowania. Nie wiedzą o innych dziedzinach ani się nimi nie przejmują. Pozostałe pola po prostu jadą, niezmienione. To sprawia, że ​​instrukcje SQL są łatwiejsze do napisania, łatwiejsze do odczytania, łatwiejsze w utrzymaniu i bardziej rozszerzalne.
  • Używane są tylko zwykłe instrukcje MySQL. Nie są wymagane żadne inne narzędzia ani języki programowania.
  • W pełni poprawny zapis jest wstawiany your_tablew jednej operacji atomowej.

3
Wygląda na to, że ta fajna sztuczka (podobało mi się, ale nie działała dla mnie) nie działa na tabelach zawierających kolumny TEXT / VARCHAR. Próbowałem i otrzymałem: (1163): Używany typ tabeli nie obsługuje kolumn BLOB / TEXT. To oczywiście bardzo ogranicza użycie MySQL! Być może w przyszłości limity te zostaną zniesione lub w innych systemach db to działa, ale na razie jest naprawdę ograniczone.
Juergen

Bardzo podoba mi się sprytne użycie tymczasowego stołu. Tak przydatne w przypadku tabel z mnóstwem kolumn!
Lasma

1
Wygląda ładnie, ale kiedy uruchamiam pierwsze zapytanie w MySQL, otrzymuję Error Code: 1113. A table must have at least 1 column.
fizyczna

3
Najlepsza odpowiedź dla wielu kolumn. Ale SET id=NULLmoże powodować błąd Column 'id' cannot be null. Powinien zostać zastąpiony przezUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder

1
@ physicalattraction musisz upewnić się, że pierwsze dwa wiersze są jedną instrukcją.
Samuurai

16

Powiedz, że stół jest user(id, user_name, user_email).

Możesz użyć tego zapytania:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)

29
Należy zawsze przy użyciu INSERT podać nazwy kolumn, inaczej dostaniesz dziwne i ciekawe błędy podczas zmiany schematu.
mu jest za krótki

2
Rzeczywiście dziwne i interesujące. : D
sparkyShorts

Nie działa z sqlite. Result: near "SELECT": syntax error
Kyb

10

Pomogło to i obsługuje kolumny BLOB / TEXT.

CREATE TEMPORARY TABLE temp_table
AS
SELECT * FROM source_table WHERE id=2;
UPDATE temp_table SET id=NULL WHERE id=2;
INSERT INTO source_table SELECT * FROM temp_table;
DROP TEMPORARY TABLE temp_table;
USE source_table;

W jaki sposób jest to lepsze niż inne odpowiedzi tutaj?
Smar

3
Myślę, że to całkiem dobrze, jeśli masz stół ze 100 polami. Z wyjątkiem tego, że identyfikator może mieć nie zerowe ograniczenie, co powoduje, że zawodzi
Loïc Faure-Lacroix,

Kod błędu: 1136. Liczba kolumn nie zgadza się z liczbą wartości w wierszu 1
Oleksii Kyslytsyn

Jest to o wiele lepsze, jeśli masz tabelę z setkami kolumn.
Tyler S. Loeper

Czy nie tak powiedział Parvus lata temu?
ToolmakerSteve

7

Aby uzyskać szybkie, czyste rozwiązanie, które nie wymaga nazywania kolumn, możesz użyć przygotowanej instrukcji, jak opisano tutaj: https://stackoverflow.com/a/23964285/292677

Jeśli potrzebujesz złożonego rozwiązania, które możesz wykonywać często, możesz skorzystać z tej procedury:

DELIMITER $$

CREATE PROCEDURE `duplicateRows`(_schemaName text, _tableName text, _whereClause text, _omitColumns text)
SQL SECURITY INVOKER
BEGIN
  SELECT IF(TRIM(_omitColumns) <> '', CONCAT('id', ',', TRIM(_omitColumns)), 'id') INTO @omitColumns;

  SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns 
  WHERE table_schema = _schemaName AND table_name = _tableName AND FIND_IN_SET(COLUMN_NAME,@omitColumns) = 0 ORDER BY ORDINAL_POSITION INTO @columns;

  SET @sql = CONCAT('INSERT INTO ', _tableName, '(', @columns, ')',
  'SELECT ', @columns, 
  ' FROM ', _schemaName, '.', _tableName, ' ',  _whereClause);

  PREPARE stmt1 FROM @sql;
  EXECUTE stmt1;
END

Możesz go uruchomić za pomocą:

CALL duplicateRows('database', 'table', 'WHERE condition = optional', 'omit_columns_optional');

Przykłady

duplicateRows('acl', 'users', 'WHERE id = 200'); -- will duplicate the row for the user with id 200
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts'); -- same as above but will not copy the created_ts column value    
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts,updated_ts'); -- same as above but also omits the updated_ts column
duplicateRows('acl', 'users'); -- will duplicate all records in the table

ZASTRZEŻENIE: To rozwiązanie jest przeznaczone tylko dla kogoś, kto często będzie powtarzał wiersze w wielu tabelach. Może być niebezpieczne w rękach nieuczciwego użytkownika.


3

Możesz również podać „0” jako wartość kolumny do automatycznego przyrostu, przy tworzeniu rekordu zostanie użyta poprawna wartość. Jest to o wiele łatwiejsze niż tabele tymczasowe.

Źródło: Kopiowanie wierszy w MySQL (patrz drugi komentarz TRiG do pierwszego rozwiązania autorstwa Lore)


1
Ta metoda działa z nowszymi wersjami MySQL, gdy wartość NULL jest niedopuszczalna.
err

3

Wiele świetnych odpowiedzi tutaj. Poniżej znajduje się przykład procedury składowanej, którą napisałem, aby wykonać to zadanie dla opracowywanej przeze mnie aplikacji sieci Web:

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

-- Create Temporary Table
SELECT * INTO #tempTable FROM <YourTable> WHERE Id = Id

--To trigger the auto increment
UPDATE #tempTable SET Id = NULL 

--Update new data row in #tempTable here!

--Insert duplicate row with modified data back into your table
INSERT INTO <YourTable> SELECT * FROM #tempTable

-- Drop Temporary Table
DROP TABLE #tempTable

w bieżącej wersji ustawienia MariaDB / MySQL id = null daje # 1048 - Kolumna „id” nie może mieć wartości null, ustawienie id = 0 działa;
shelbypereira

2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

3
Jak to jest lepsze niż inne odpowiedzi tutaj?
Smar

1
@smar imo łatwiej zrozumieć
Satbir Kira,

2

Jeśli możesz używać MySQL Workbench, możesz to zrobić, klikając prawym przyciskiem myszy wiersz i wybierając „Kopiuj wiersz”, a następnie klikając prawym przyciskiem myszy pusty wiersz i wybierając „Wklej wiersz”, a następnie zmieniając identyfikator, a następnie klikając „Zastosuj”.

Skopiuj wiersz:

wprowadź opis zdjęcia tutaj

Wklej skopiowany wiersz do pustego wiersza:

wprowadź opis zdjęcia tutaj

Zmień identyfikator:

wprowadź opis zdjęcia tutaj

Zastosować:

wprowadź opis zdjęcia tutaj


0

Szukałem tej samej funkcji, ale nie używam MySQL. Chciałem skopiować WSZYSTKIE pola oprócz oczywiście klucza podstawowego (id). To było zapytanie jednorazowe, którego nie można używać w żadnym skrypcie ani kodzie.

Znalazłem się w PL / SQL, ale jestem pewien, że zrobiłoby to każde inne IDE SQL. Zrobiłem podstawowy

SELECT * 
FROM mytable 
WHERE id=42;

Następnie wyeksportuj go do pliku SQL, w którym mógłbym znaleźć

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (1, 2, 3, ..., 42);

Właśnie go edytowałem i użyłem:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);

0

Zwykle używam odmiany tego, co mu jest zbyt krótkie:

INSERT INTO something_log
SELECT NULL, s.*
FROM something AS s
WHERE s.id = 1;

Tak długo, jak tabele mają identyczne pola (z wyjątkiem automatycznego przyrostu w tabeli dziennika), działa to dobrze.

Ponieważ w miarę możliwości korzystam z procedur przechowywanych (aby ułatwić życie innym programistom, którzy nie są zbyt obeznani z bazami danych), rozwiązuje to problem konieczności cofania się i aktualizowania procedur za każdym razem, gdy dodajesz nowe pole do tabeli.

Zapewnia również, że jeśli dodasz nowe pola do tabeli, natychmiast zaczną pojawiać się w tabeli dziennika bez konieczności aktualizowania zapytań do bazy danych (chyba że masz takie, które wyraźnie ustawiają pole)

Ostrzeżenie: Pamiętaj, aby dodać nowe pola do obu tabel jednocześnie, aby kolejność pól pozostała taka sama ... w przeciwnym razie zaczniesz otrzymywać dziwne błędy. Jeśli jesteś jedynym, który pisze interfejsy bazy danych ORAZ jesteś bardzo ostrożny, to działa dobrze. W przeciwnym razie trzymaj się nazewnictwa wszystkich swoich pól.

Uwaga: Z drugiej strony, chyba że pracujesz nad projektem solowym, masz pewność, że inni nie będą pracować nad tym, aby jawnie wypisywać wszystkie nazwy pól i aktualizować instrukcje dziennika w miarę zmiany schematu. Ten skrót prawdopodobnie nie jest wart długoterminowego bólu głowy, który może powodować ... zwłaszcza w systemie produkcyjnym.


0
WSTAW DO `dbMyDataBase` .tblMyTable` 
(
    „IdAutoincrement”, 
    „Kolumna2”, 
    „Kolumna3”, 
    `Kolumna4` 
) 

WYBIERZ 
    ZERO,  
    „Kolumna2”, 
    „Kolumna3”, 
    Kolumna „CustomValue” AS 
FROM `dbMyDataBase` .tblMyTable` 
GDZIE `tblMyTable``Column2` = 'UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /

3
Spróbuj dodać bardziej szczegółowe wyjaśnienie lub sposób, w jaki rozszerza się to na inne odpowiedzi
Azsgy,

-1

Zrzuć wiersz, który chcesz sql, a następnie użyj wygenerowanego kodu SQL, bez kolumny identyfikatora, aby zaimportować go ponownie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.