programing tip

MySQL에서 하나의 행을 복사하여 동일한 테이블에 삽입 할 수 있습니까?

itbloger 2020. 6. 14. 11:04
반응형

MySQL에서 하나의 행을 복사하여 동일한 테이블에 삽입 할 수 있습니까?


insert into table select * from table where primarykey=1

동일한 테이블에 삽입하기 위해 하나의 행을 복사하려고합니다 (예 : 테이블의 기존 행을 복제하려고 함). "select"뒤에 모든 열을 나열하지 않고도이 작업을 수행하려고합니다. 열이 너무 많습니다.

그러나이 작업을 수행하면 오류가 발생합니다.

키 1의 중복 된 항목 'xxx'

복사하려는 레코드의 임시 컨테이너와 동일한 열로 다른 테이블을 작성하여이를 처리 할 수 ​​있습니다.

create table oldtable_temp like oldtable;
insert into oldtable_temp select * from oldtable where key=1;
update oldtable_tem set key=2;
insert into oldtable select * from oldtable where key=2;

이것을 해결하는 더 간단한 방법이 있습니까?


Leonard Challis의 기술을 몇 가지 변경 사항으로 사용했습니다.

CREATE TEMPORARY TABLE tmptable_1 SELECT * FROM table WHERE primarykey = 1;
UPDATE tmptable_1 SET primarykey = NULL;
INSERT INTO table SELECT * FROM tmptable_1;
DROP TEMPORARY TABLE IF EXISTS tmptable_1;

임시 테이블로서 하나 이상의 레코드가 없어야하므로 기본 키에 대해 걱정할 필요가 없습니다. null로 설정하면 MySQL이 값 자체를 선택할 수 있으므로 복제본을 만들 위험이 없습니다.

확실하게 삽입하려면 한 행만 삽입하면 INSERT INTO 행 끝에 LIMIT 1을 추가 할 수 있습니다.

또한 기본 키 값 (이 경우 1)을 임시 테이블 이름에 추가했습니다.


Update 07/07/2014- Grim ...의 내 대답을 기반으로 한 답변 은 아래의 솔루션을 개선함에 따라 더 나은 솔루션이므로 사용하는 것이 좋습니다.

다음 구문으로 모든 열을 나열하지 않고도이 작업을 수행 할 수 있습니다.

CREATE TEMPORARY TABLE tmptable SELECT * FROM table WHERE primarykey = 1;
UPDATE tmptable SET primarykey = 2 WHERE primarykey = 1;
INSERT INTO table SELECT * FROM tmptable WHERE primarykey = 2;

다른 방법으로 기본 키를 변경하기로 결정할 수 있습니다.


나는 당신이 새로운 레코드가 새로운 것을 갖기를 원한다고 가정합니다 primarykey. 경우 primarykey입니다 AUTO_INCREMENT그럼 그냥 이렇게 :

INSERT INTO table (col1, col2, col3, ...)
SELECT col1, col2, col3, ... FROM table
  WHERE primarykey = 1

...를 제외하고col1, col2, col3, ... 표의 모든 열이 있습니다. primarykey

AUTO_INCREMENT이 아니며 새 값을 선택할 수 있도록하려면 primarykey다음과 유사합니다.

INSERT INTO table (primarykey, col2, col3, ...)
SELECT 567, col2, col3, ... FROM table
  WHERE primarykey = 1

... 567의 새로운 가치는 어디입니까 primarykey?


첫 번째 쿼리에서 거의 열을 지정해야 했으므로 삽입에서 기본 키를 제외하여 테이블에서 자동 증가를 수행하여 테이블에 대한 새 기본 키를 자동으로 만들 수 있습니다. 기입.

예를 들어 다음을 변경하십시오.

insert into table select * from table where primarykey=1

이에:

INSERT INTO table (col1, col2, col3) 
SELECT col1, col2, col3 
FROM table 
WHERE primarykey = 1

INSERT 또는 쿼리의 SELECT 부분에 대한 열 목록에 기본 키 열을 포함시키지 마십시오.


테이블 덤프, 삽입 명령 찾기 및 편집을 시도 할 수도 있습니다.

mysqldump -umyuser -p mydatabase --skip-extended-insert mytable > outfile.sql

--skip-extended-insert당신에게 행 당 하나 개의 삽입 명령을 제공합니다. 그런 다음 자주 사용하는 텍스트 편집기에서 행을 찾고 명령을 추출한 후 기본 키를 "default"로 변경하십시오.


이 절차는 다음을 가정합니다.

  • _duplicate_temp_table이 없습니다
  • 기본 키는 int입니다
  • 당신은 테이블을 만들 수있는 권한이

물론 이것은 완벽하지는 않지만 특정 (아마도 대부분의 경우) 효과가 있습니다.

DELIMITER $$
CREATE PROCEDURE DUPLICATE_ROW(copytable VARCHAR(255), primarykey VARCHAR(255), copyid INT, out newid INT)
BEGIN
        DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @error=1;
        SET @temptable = '_duplicate_temp_table';
        SET @sql_text = CONCAT('CREATE TABLE ', @temptable, ' LIKE ', copytable);
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('INSERT INTO ', @temptable, ' SELECT * FROM ', copytable, ' where ', primarykey,'=', copyid);
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('SELECT max(', primarykey, ')+1 FROM ', copytable, ' INTO @newid');
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('UPDATE ', @temptable, ' SET ', primarykey, '=@newid');
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('INSERT INTO ', copytable, ' SELECT * FROM ', @temptable, '');
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET @sql_text = CONCAT('DROP TABLE ', @temptable);
        PREPARE stmt FROM @sql_text;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SELECT @newid INTO newid;
END $$
DELIMITER ;

CALL DUPLICATE_ROW('table', 'primarykey', 1, @duplicate_id);
SELECT @duplicate_id;

테이블의 기본 키 필드가 자동 증분 필드 인 경우 열과 함께 쿼리를 사용할 수 있습니다. 예를 들어, 이름 test_tbl지정된 테이블 에는로 3 개의 필드가 id, name, age있습니다. id은 기본 키 필드이며 자동 증분이므로 다음 쿼리를 사용하여 행을 복제 할 수 있습니다.

INSERT INTO `test_tbl` (`name`,`age`) SELECT `name`,`age` FROM `test_tbl`;

이 쿼리는 모든 행을 복제합니다.


테이블의 기본 키 필드가 자동 증분 필드가 아닌 경우 다음 방법을 사용할 수 있습니다.

INSERT INTO `test_tbl` (`id`,`name`,`age`)
  SELECT 20,`name`,`age` FROM `test_tbl` WHERE id = 19;

이 쿼리의 결과는로 id=19삽입 된 중복 행입니다 id=20.


이것은 몇 가지 창의력으로 달성 할 수 있습니다.

SET @sql = CONCAT('INSERT INTO <table> SELECT null, 
    ', (SELECT GROUP_CONCAT(COLUMN_NAME) 
    FROM information_schema.columns 
    WHERE table_schema = '<database>' 
    AND table_name = '<table>' 
    AND column_name NOT IN ('id')), ' 
from <table> WHERE id = <id>');  

PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

그러면 새 행이 선택한 행의 ID 대신 자동 증분 ID를 얻습니다.


이 사이트에서 다음 중 일부를 수집했습니다. 이것은 여러 필드가있는 테이블의 레코드를 복제하기 위해 수행 한 작업입니다.

이것은 또한 테이블의 시작 부분에 AI 필드가 있다고 가정합니다.

function duplicateRow( $id = 1 ){
dbLink();//my db connection
$qColumnNames = mysql_query("SHOW COLUMNS FROM table") or die("mysql error");
$numColumns = mysql_num_rows($qColumnNames);

for ($x = 0;$x < $numColumns;$x++){
$colname[] = mysql_fetch_row($qColumnNames);
}

$sql = "SELECT * FROM table WHERE tableId = '$id'";
$row = mysql_fetch_row(mysql_query($sql));
$sql = "INSERT INTO table SET ";
for($i=1;$i<count($colname)-4;$i++){//i set to 1 to preclude the id field
//we set count($colname)-4 to avoid the last 4 fields (good for our implementation)
$sql .= "`".$colname[$i][0]."`  =  '".$row[$i]. "', ";
}
$sql .= " CreateTime = NOW()";// we need the new record to have a new timestamp
mysql_query($sql);
$sql = "SELECT MAX(tableId) FROM table";
$res = mysql_query($sql);
$row = mysql_fetch_row($res);
return $row[0];//gives the new ID from auto incrementing
}

업데이트 필드와 자동 증분 값이있는 복제 행

CREATE TEMPORARY TABLE `temp` SELECT * FROM `testing` WHERE id = 14;

UPDATE `temp` SET id = (SELECT id FROM testing ORDER by id DESC LIMIT 1
 )+1, user_id = 252 ,policy_no = "mysdddd12" where id = 14;

INSERT INTO `testing` SELECT * FROM `temp`;

DROP TEMPORARY TABLE IF EXISTS `temp`;

나는 이것에 늦을지도 모르지만 비슷한 해결책이 있습니다.

 INSERT INTO `orders` SELECT MAX(`order_id`)+1,`container_id`, `order_date`, `receive_date`, `timestamp` FROM `orders` WHERE `order_id` = 1

이렇게하면 임시 테이블 등을 만들 필요가 없습니다. 행이 동일한 테이블에 복사되므로 Max(PK)+1함수를 쉽게 사용할 수 있습니다.

나는이 질문의 해결책을 찾고 있었고 (구문을 잊어 버렸다) 나는 내 자신의 쿼리를 만들었습니다. 상황이 몇 번이나 잘 풀리는 방식이 재미 있습니다.

문안 인사


기본 키가 자동 증분 인 경우 기본 키를 제외한 각 필드를 지정하십시오.

INSERT INTO table(field1,field2,field3) SELECT (field1,field2,field3) FROM table WHERE primarykey=1


@LeonardChallis의 솔루션은 다른 어느 누구도 나를 위해 작동하지 않았으므로 업데이트했습니다. MySQL에서 WHERE조항과 SET primaryKey = 0임시 테이블을 제거하여 MySQL이 기본 키를 자동 증가시킵니다.

CREATE TEMPORARY TABLE tmptable SELECT * FROM myTable;
UPDATE tmptable SET primaryKey = 0;
INSERT INTO myTable SELECT * FROM tmptable;

이것은 물론 테이블의 모든을 복제 하는 것입니다.


아래에서 사용하겠습니다.

insert into ORDER_ITEM select * from ORDER_ITEM where ITEM_NUMBER =123;

Koha 데이터베이스 에서 바코드 열에 'C'접두사가 붙은 중복 항목을 삽입 하는 데 사용했습니다 .

INSERT INTO items (`biblionumber`, `biblioitemnumber`, `barcode`, `dateaccessioned` ) SELECT `biblionumber`, `biblioitemnumber`,  CONCAT('C',`barcode`), `dateaccessioned` FROM `items` WHERE barcode='14832';

방금이 작업을 수행해야했으며 이것이 내 수동 솔루션이었습니다.

  1. 에서 phpMyAdmin에 , 복사 할 행을 확인
  2. 쿼리 결과 작업 아래에서 '내보내기'를 클릭하십시오.
  3. 다음 페이지에서 '파일로 저장'확인한 다음 '이동' 을 클릭하십시오
  4. 텍스트 편집기로 내 보낸 파일을 열고 기본 필드의 값을 찾아 고유 한 값으로 변경하십시오.
  5. 돌아 가기 하면 phpMyAdmin 온 클릭 '가져 오기' 탭에서 .SQL 파일을 가져올 파일의 위치를 찾아 클릭 '이동' 과 중복 행이 삽입되어야한다.

PRIMARY 필드가 무엇인지 모르는 경우 , phpmyadmin 페이지를 다시 살펴보고 'Structure' 탭을 클릭 하고 페이지 하단의 'Indexes' 아래 'Keyname' 이있는 ' Field'표시됩니다 'PRIMARY'.

일종의 먼 길이지만 마크 업을 처리하고 싶지 않고 단일 행을 복제 해야하는 경우 이동하십시오.


Grim의 기술을 약간 변경하여 사용했습니다.이 쿼리를 찾는 사람이 기본 키 문제로 인해 간단한 쿼리를 수행 할 수 없기 때문에 :

INSERT INTO table SELECT * FROM table WHERE primakey=1;

MySql 설치 5.6.26을 사용하면 키를 null 수 없으며 오류가 발생합니다.

#1048 - Column 'primakey' cannot be null 

따라서 임시 테이블을 만든 후 기본 키를 nullable로 변경합니다.

CREATE TEMPORARY TABLE tmptable_1 SELECT * FROM table WHERE primarykey = 1;
ALTER TABLE tmptable_1 MODIFY primarykey int(12) null;
UPDATE tmptable_1 SET primarykey = NULL;
INSERT INTO table SELECT * FROM tmptable_1;
DROP TEMPORARY TABLE IF EXISTS tmptable_1;

이 솔루션은 선택된 행에도 완벽하게 작동한다는 것을 보여주었습니다. 예를 들어 nice2work 프로젝트에 대한 데모 행을 작성 중이며 완벽하게 작동합니다.

CREATE TEMPORARY TABLE tmptable SELECT * FROM myTable WHERE id=500;
UPDATE tmptable SET id = 0;
UPDATE some fields I need to change
INSERT INTO myTable SELECT * FROM tmptable;
DROP TABLE tmptable;

//  You can use this same also directly into your code like (PHP Style)
$sql = "CREATE TEMPORARY TABLE tmptable SELECT * FROM myTable WHERE id=500;
UPDATE tmptable SET id = 0;
UPDATE some fields I need to change
INSERT INTO myTable SELECT * FROM tmptable;DROP TABLE tmptable;";

네크로 포스트는 미안하지만 이것은 구글로 밝혀졌으며 이것이 도움이되었지만 문제가 있음을 알게 된 이후 이것을 파는 다른 사람에게 중요한 수정을하고자했습니다.

먼저 MySQL이 아닌 SQL Server를 사용하고 있지만 비슷하게 작동해야한다고 생각합니다. Leonard Challis의 솔루션은 가장 간단하고 필요를 충족했기 때문에 사용했지만 문제가 있습니다 .PK를 가져 와서 1 씩 늘리면 문제의 행이 추가 된 후 다른 레코드를 추가하면 어떻게됩니까? . 시스템이 PK의 자동 증가를 처리하도록하는 것이 최선이라고 결정했기 때문에 다음을 수행했습니다.

SELECT * INTO #tmpTable FROM Table WHERE primarykey = 1
--Optionally you can modify one or more fields here like this: 
--UPDATE #tmpTable SET somefield = newData
ALTER TABLE #tmpTable DROP COLUMN TicketUpdateID
INSERT INTO Tickets SELECT * FROM #tmpTable
DROP TABLE #tmpTable

I believe this would work similarly in MySQL, but I can't test this, sorry


I know it's an old question, but here is another solution:

This duplicates a row in the main table, assuming the primary key is auto-increment, and creates copies of linked-tables data with the new main table id.

Other options for getting column names:
-SHOW COLUMNS FROM tablename; (Column name: Field)
-DESCRIBE tablename (Column name: Field)
-SELECT column_name FROM information_schema.columns WHERE table_name = 'tablename' (Column name: column_name)

//First, copy main_table row
$ColumnHdr='';
$Query="SHOW COLUMNS FROM `main_table`;";
$Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__);
while($Row=mysql_fetch_array($Result))
{
    if($Row['Field']=='MainTableID')     //skip main table id in column list
        continue;
    $ColumnHdr.=",`" . $Row['Field'] . "`";
}
$Query="INSERT INTO `main_table` (" . substr($ColumnHdr,1) . ")
        (SELECT " . substr($ColumnHdr,1) . " FROM `main_table`
            WHERE `MainTableID`=" . $OldMainTableID . ");";
$Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__);
$NewMainTableID=mysql_insert_id($link);

//Change the name (assumes a 30 char field)
$Query="UPDATE `main_table` SET `Title`=CONCAT(SUBSTRING(`Title`,1,25),' Copy') WHERE `MainTableID`=" . $NewMainTableID . ";";
$Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__);

//now copy in the linked tables
$TableArr=array("main_table_link1","main_table_link2","main_table_link3");
foreach($TableArr as $TableArrK=>$TableArrV)
{
    $ColumnHdr='';
    $Query="SHOW COLUMNS FROM `" . $TableArrV . "`;";
    $Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__);
    while($Row=mysql_fetch_array($Result))
    {
        if($Row['Field']=='MainTableID')     //skip main table id in column list, re-added in query
            continue;
        if($Row['Field']=='dbID')    //skip auto-increment,primary key in linked table
            continue;
        $ColumnHdr.=",`" . $Row['Field'] . "`";
    }

    $Query="INSERT INTO `" . $TableArrV . "` (`MainTableID`," . substr($ColumnHdr,1) . ")
            (SELECT " . $NewMainTableID . "," . substr($ColumnHdr,1) . " FROM `" . $TableArrV . "`
             WHERE `MainTableID`=" . $OldMainTableID . ");";
    $Result=Wrappedmysql_query($Query,$link,__FILE__,__LINE__);
}

max233 was certainly on the right track, at least for the autoincrement case. However, do not do the ALTER TABLE. Simply set the auto-increment field in the temporary table to NULL. This will present an error, but the following INSERT of all fields in the temporary table will happen and the the NULL auto field will obtain a unique value.


Create a table

    CREATE TABLE `sample_table` (
       `sample_id` INT(10) unsigned NOT NULL AUTO_INCREMENT,
       `sample_name` VARCHAR(255) NOT NULL,
       `sample_col_1` TINYINT(1) NOT NULL,
       `sample_col_2` TINYINT(2) NOT NULL,

      PRIMARY KEY (`sample_id`),
      UNIQUE KEY `sample_id` (`sample_id`)

    ) ENGINE='InnoDB' DEFAULT CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

Insert a row

INSERT INTO `sample_table`
   VALUES(NULL, 'sample name', 1, 2);

Clone row insert above

INSERT INTO `sample_table`
   SELECT 
    NULL AS `sample_id`, -- new AUTO_INCREMENT PRIMARY KEY from MySQL
    'new dummy entry' AS `sample_name`,  -- new UNIQUE KEY from you
    `sample_col_1`, -- col from old row
    `sample_col_2` -- col from old row
   FROM `sample_table`
   WHERE `sample_id` = 1;

Test

SELECT * FROM `sample_table`;

Here's an answer I found online at this site Describes how to do the above1 You can find the answer at the bottom of the page. Basically, what you do is copy the row to be copied to a temporary table held in memory. You then change the Primary Key number using update. You then re-insert it into the target table. You then drop the table.

This is the code for it:

CREATE TEMPORARY TABLE rescueteam ENGINE=MEMORY SELECT * FROMfitnessreport4 WHERE rID=1;# 1 row affected. UPDATE rescueteam SET rID=Null WHERE rID=1;# 1 row affected.INSERT INTO fitnessreport4 SELECT * FROM rescueteam;# 1 row affected. DROP TABLE rescueteam# MySQL returned an empty result set (i.e. zero
rows).

I created the temporary table rescueteam. I copied the row from my original table fitnessreport4. I then set the primary key for the row in the temporary table to null so that I can copy it back to the original table without getting a Duplicate Key error. I tried this code yesterday evening and it worked.


For a very simple solution, you could use PHPMyAdmin to export the row as a CSV file then simply import the amended CSV file. Editing the ID/primarykey column to show no value before you import it.

SELECT * FROM table where primarykey=1

Then at the bottom of the page:

enter image description here

Where is says "Export" simply export, then edit the csv file to remove the primarykey value, so it's empty, and then just import it into the database, a new primarykey will be assigned on import.


Just wanted to post my piece of PHP code, because I think the way I collect the columns is a bit cleaner in code than the previous examples. Also this shows how you could easily alter an field, in this case adding a string. But you could also replace a foreign key field with the newly added record, in case you want to copy some child records as well.

  // Read columns, unset the PK (always the first field in my case)
  $stmt = $conn->prepare('SHOW COLUMNS FROM template');
  $stmt->execute();

  $columns = $stmt->fetchAll();
  $columns = array_map(function ($element) { return $element['Field']; }, $columns);

  unset($columns[0]);

  // Insert record in the database. Add string COPY to the name field.
  $sql = "INSERT INTO `template` (".implode(",", $columns).")";
  if ($key = array_search('name', $columns))
      $columns[$key] = "CONCAT(name, ' COPY')";
  $sql .= " SELECT ".implode(",", $columns)." FROM `template` WHERE `id` = ".$id;

  $stmt = $conn->prepare($sql);
  $stmt->execute();

참고URL : https://stackoverflow.com/questions/4039748/in-mysql-can-i-copy-one-row-to-insert-into-the-same-table

반응형