동일한 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 : 나는 잘 알고 NULL와 0동일하지 않습니다. 현재 컨텍스트가 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.