동일한 MySQL 테이블에서 레코드 복제 / 복사


87

나는 한동안 찾고 있었지만 내 문제에 대한 쉬운 해결책을 찾을 수 없습니다. 테이블에 레코드를 복제하고 싶지만 물론 고유 한 기본 키를 업데이트해야합니다.

이 쿼리가 있습니다.

INSERT INTO invoices
    SELECT * FROM invoices AS iv WHERE iv.ID=XXXXX
    ON DUPLICATE KEY UPDATE ID = (SELECT MAX(ID)+1 FROM invoices)

문제는 이것이 ID행을 복사하는 대신 행의를 변경한다는 것 입니다. 아무도 이것을 고치는 방법을 알고 있습니까?

// 편집 : 필드 이름은 시간이 지남에 따라 변경 될 수 있으므로 모든 필드 이름을 입력하지 않고이 작업을 수행하고 싶습니다.

답변:


137

내가 보통가는 방식은 임시 테이블을 사용하는 것입니다. 아마도 계산적으로 효율적이지는 않지만 정상적으로 작동하는 것 같습니다! 여기서는 99 번 레코드를 전체적으로 복제하여 100 번 레코드를 만듭니다.

CREATE TEMPORARY TABLE tmp SELECT * FROM invoices WHERE id = 99;

UPDATE tmp SET id=100 WHERE id = 99;

INSERT INTO invoices SELECT * FROM tmp WHERE id = 100;

그것이 당신을 위해 잘 작동하기를 바랍니다!


나는 그것을 좋아한다, 사물을 주시하기 위해 중간에 한 걸음
SeanDowney 2011 년

4
단일 레코드를 복사하는 경우 업데이트와 삽입 모두에서 위치를 삭제할 수 있습니다. 그런 다음 mysql 콘솔에서 두 번 눌러 역사의 마지막 작업을 불러오고, 마지막에 편리한 업데이트에서 ID를 변경하고, Enter 키를 누르고, 위로 누르고, 아무것도 변경하지 않고 다시 Enter 키를 누른 다음 반복하십시오. 여러 사본에 대한 절차. 훨씬 더 빨리.
Cristian Vrabie

4
ID 100이 이미있는 경우 두 번째로 새 행에 대해 새 ID를 선택하고 작업 중에 다른 사람이 새 행을 삽입하면 사용자의 ID와 새로 삽입 된 ID가 동일합니다. 이것은이 코드의 병목입니다.
nbhatti2001

6
NULL을 사용할 수 있습니다.CREATE TEMPORARY TABLE tmp SELECT bla FROM invoices WHERE bla; UPDATE tmp SET id=NULL; INSERT INTO invoices SELECT * FROM tmp;
Tobias Beuving 2015-08-31

1
@TobiasBeuving을 NOT NULL설정 했기 때문에 복사 붙여 넣기 오류 메시지 입니다 id. 이 사건에 대한 제안이 있는지 궁금합니다. 그것은 나쁜 습관으로 간주됩니까?
Marcel

84

Alex의 대답은 다중 클라이언트 환경에서 약간의주의 (예 : 잠금 또는 트랜잭션)가 필요합니다.

AUTO ID필드가 테이블의 첫 번째 필드 (일반적인 경우) 라고 가정하면 암시 적 트랜잭션을 사용할 수 있습니다.

    CREATE TEMPORARY TABLE tmp SELECT * from invoices WHERE ...;
    ALTER TABLE 임시 삭제 ID; # 자동 증가 필드 삭제
    # tmp SET 업데이트 ...; # 다른 고유 키를 변경하는 데 필요
    INSERT INTO 인보이스 SELECT 0, tmp. * FROM tmp;
    DROP TABLE tmp;

MySQL 문서에서 :

AUTO_INCREMENT 사용 : 열에 NULL 또는 0을 명시 적으로 할당하여 시퀀스 번호를 생성 할 수도 있습니다.


이렇게하면 AUTO_INCREMENT 필드가 있어도 ID가 0 인 레코드가 들어갑니다. null로 변경하면 작동하므로 0 대신 null을 사용하도록 코드를 변경하는 것이 좋습니다. 저는 MySQL 5.5.35 (Ubuntu)를 사용하고 있습니다.
Tyler Collier

@TylerCollier : NULL또는 0둘 다 허용됩니다. 여기에서 문제를 재현하고 공유하여 문제의 스크린 샷을 게시 할 수 있습니까?
Ravinder Reddy 2014

4 번 줄의 neato 하위 쿼리를 이해하려고하면 뇌가 아팠습니다.이 설명이 도움이 될 수 있습니다. 대상 테이블 invoices에 AUTO_INCREMENT ID필드가 있습니다. 소스 테이블 tmp은 그렇지 않습니다. 삽입하는 동안 필요한 1 : 1 상관 관계를 얻으려면 0대상 테이블의 AUTO_INCREMENT 필드 인 선택의 첫 번째 필드로 를 지정 합니다. tmp.*선택 소스 테이블의 모든 필드 tmp. 완전한! 이제 1 : 1 상관 관계가 있습니다. 굉장한 대답 @ 팀.
elbowlobstercowstand

@RavinderReddy NULL과 0은 동일하지 않습니다 - 이런 종류의 물건에 대한 사용 NULL은 0 - 기록 - ID를 가질 수 있습니다
토비아스 Beuving

@TobiasBeuving : 나는 잘 알고 NULL0동일하지 않습니다. 현재 컨텍스트가 AUTO_INCREMENT기능 에 있습니다. 이러한 필드 에는 0또는 NULL값을 삽입 할 수 없습니다 . 그러나 이러한 필드를 입력으로 사용하면 다음 시퀀스 값이 해당 필드에 자동 으로 할당됩니다 . 따라서 내 의견. SQL 바이올린에 대한 증명 : sqlfiddle.com/#!9/d619f/1
레빈 더 레디

12

DUPLICATE KEY가 트리거된다는 것을 확실히 알고 있으므로 미리 MAX (ID) +1을 선택할 수 있습니다.

INSERT INTO invoices SELECT MAX(ID)+1, ... other fields ... FROM invoices AS iv WHERE iv.ID=XXXXX 

2
예,하지만 다른 모든 필드를 입력하고 싶지 않습니다 (20 개 정도가 있으며 시간이 지남에 따라 변경 될 수 있음). tablestructre가 변경 될 때마다 코드를 변경하고 싶지 않습니다.
Digits

당신은해야합니다. 필드 목록에서 SQL 문을 생성하는 스크립트를 만드는 것이 좋습니다. 사소한 일입니다.
Ingo

유일한 다른 대안은 삽입 트리거를 사용하는 것입니다 (mysql이 지원하는 경우).
Ingo

11

접근 방식은 좋지만 문제는 필드 이름을 등록하는 대신 "*"를 사용한다는 것입니다. 기본 키를 제외한 모든 열 이름을 입력하면 스크립트가 하나 또는 여러 레코드에서 매력처럼 작동합니다.

INSERT INTO invoices (iv.field_name, iv.field_name,iv.field_name ) SELECT iv.field_name, iv.field_name,iv.field_name FROM invoices AS iv WHERE iv.ID=XXXXX


그러나 이는 필드가 테이블에 추가되거나 테이블에서 삭제되는 즉시 코드를 변경해야 함을 의미하며, 개인적으로 MAJOR no-no를 찾습니다. (항상 그렇지,하지만 자주.)
뢰머

10

내가 아는 늦은 답변이지만 여전히 일반적인 질문입니다. 한 줄 insert into문만 사용하여 저에게 효과적이라는 또 다른 답변을 추가 하고 싶습니다. 새 테이블을 만들지 않고도 간단하다고 생각합니다. CREATE TEMPORARY TABLE권한 문제 ) :

INSERT INTO invoices (col_1, col_2, col_3, ... etc)
  SELECT
    t.col_1,
    t.col_2,
    t.col_3,
    ...
    t.updated_date,
  FROM invoices t;

솔루션은 AUTO_INCREMENTid 열에 대해 작동합니다 . 그렇지 않으면 ID문에도 열을 추가 할 수 있습니다 .

INSERT INTO invoices (ID, col_1, col_2, col_3, ... etc)
  SELECT
    MAX(ID)+1,
    t.col_1,
    t.col_2,
    t.col_3,
    ... etc ,
  FROM invoices t;

정말 쉽고 간단합니다. 나중에 두 번째 업데이트 문없이 한 줄로 다른 것을 업데이트 할 수 있습니다 (예 : 제목 열을 추가 텍스트로 업데이트하거나 문자열을 다른 문자열로 대체). 복제하고 싶을 때만 가능하면 복제 할 수 있습니다.


2
이것은 또한 복사하는 동안 일부 필드를 수정하기위한 좋은 기초입니다. INSERT into wp_options SELECT NULL, 'theme_mods_twopress', option_value, autoload FROM wp_options where option_name = 'theme_mods_onepress';항목 ( AUTO_INCREMENT NULL위에서 트릭)과 option_name필드 를 늘리면서 복사하는 데 사용 했습니다 .
Marcel Waldvogel 2017

네 .. 좋은 생각입니다. 감사합니다!!
라구 Natarajan를

최상의 솔루션
Erlon Charles

3

전체 레코드 세트를 복제하려는 경우 적합하도록 Alex의 훌륭한 답변을 확장하고 싶었습니다.

SET @x=7;
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices;
UPDATE tmp SET id=id+@x;
INSERT INTO invoices SELECT * FROM tmp;

나는 이것을해야했고 Alex의 대답이 완벽한 출발점이라는 것을 알았습니다!. 물론 @x를 테이블에서 가장 높은 행 번호로 설정해야합니다 (쿼리를 통해 얻을 수 있다고 확신합니다). 이것은 매우 특정한 상황에서만 유용하므로 모든 행을 복제하지 않으려는 경우주의해서 사용하십시오. 필요에 따라 수학을 조정합니다.


2

비슷한 문제가 있으며 이것이 내가하는 일입니다.

insert into Preguntas  (`EncuestaID`, `Tipo` , `Seccion` , `RespuestaID` , `Texto` )  select '23', `Tipo`, `Seccion`, `RespuestaID`, `Texto` from Preguntas where `EncuestaID`= 18

Preguntas 방문 :

CREATE TABLE IF NOT EXISTS `Preguntas` (
  `ID` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `EncuestaID` int(11) DEFAULT NULL,
  `Tipo` char(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  `Seccion` int(11) DEFAULT NULL,
  `RespuestaID` bigint(11) DEFAULT NULL,
  `Texto` text COLLATE utf8_unicode_ci ,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=522 ;

따라서 ID가 자동으로 증가하고 EncuestaID.


죄송합니다, 단지 실현 나는이 나던이 적용되도록 열 이름을 사용하려는 해달라고
알렉스 안젤리에게

1

이것도 필요했습니다. 내 해결책은 SQLYOG (무료 버전)를 사용하여 원하는 레코드를 SQL (삽입 생성)로 내보내는 것입니다.

그런 다음 자동 생성되어야하므로 ID를 제거하기 위해 이것을 손으로 편집 한 다음 삽입을 SQLYog에 복사하여 실행했습니다. 이것은 고통스럽지 않았습니다. 다른 많은 MySQL GUI도이 작업을 수행 할 수 있다고 생각합니다.

이것은 라이브 시스템에서 테스트 목적으로 사용할 수있는 기록을 제공합니다.

이제 테이블이 매일 다시 작성되므로 재사용을 위해이 삽입물도 있습니다.


0

약간의 변형, 주요 차이점은 기본 키 필드 ( "varname")를 null로 설정하는 것입니다. 이는 경고를 생성하지만 작동합니다. 기본 키를 null로 설정하면 마지막 문에 레코드를 삽입 할 때 자동 증가가 작동합니다.

이 코드는 이전 시도도 정리하며 문제없이 두 번 이상 실행할 수 있습니다.

DELETE FROM `tbl` WHERE varname="primary key value for new record";
DROP TABLE tmp;
CREATE TEMPORARY TABLE tmp SELECT * FROM `tbl` WHERE varname="primary key value for old record";
UPDATE tmp SET varname=NULL;
INSERT INTO `tbl` SELECT * FROM tmp;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.