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.