insert into table select * from table where primarykey=1
1つの行をコピーして同じテーブルに挿入したいだけです(つまり、テーブル内の既存の行を複製したい)が、このテーブルには列が多すぎます。
しかし、これを行うと、エラーが発生します:
キー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が値自体を選択できるため、複製を作成するリスクはありません。
挿入する行が1つだけになるようにしたい場合は、INSERT INTO行の末尾にLIMIT 1を追加できます。
また、一時テーブル名に主キー値(この場合は1)を追加したことに注意してください。
更新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部分の列リストにprimarykey列を含めないでください。
テーブルをダンプして、挿入コマンドを見つけて編集することもできます。
mysqldump -umyuser -p mydatabase --skip-extended-insert mytable > outfile.sql
--skip-extended-insert
は、行ごとに1つの挿入コマンドを提供します。次に、お気に入りのテキストエディタで行を見つけ、コマンドを抽出して、プライマリキーを「デフォルト」に変更します。
この手順では、次のことを前提としています。
もちろん、これは完全ではありませんが、特定の(おそらくほとんどの)場合に機能します。
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;
これは、ある程度の創造性で実現できます。
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を取得します。
テーブルの主キーフィールドが自動インクリメントフィールドである場合、クエリを列で使用できます。たとえば、test_tbl
という名前のテーブルには、id, name, age
という3つのフィールドがあります。 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
として挿入されます。
以下のいくつかは、このサイトから収集されました。これは、任意の数のフィールドを持つテーブルのレコードを複製するためにしたことです:
これは、表の先頭に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
}
以下を使用します
insert into ORDER_ITEM select * from ORDER_ITEM where ITEM_NUMBER =123;
更新フィールドと自動インクリメント値を含む行のクローン
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のソリューションを更新しました。他のソリューションとしては機能しなかったためです。一時テーブルのWHERE
句とSET primaryKey = 0
を削除して、MySQLがprimaryKeyを自動インクリメントするようにしました
CREATE TEMPORARY TABLE tmptable SELECT * FROM myTable;
UPDATE tmptable SET primaryKey = 0;
INSERT INTO myTable SELECT * FROM tmptable;
もちろん、これはallテーブルの行を複製することです。
上記に示したこのソリューションは、選択した行にも最適です。たとえば、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;";
私はGrimの手法を少し変更して使用しました。このクエリを探している人が主キーの問題のために単純なクエリを実行できないためである場合:
INSERT INTO table SELECT * FROM table WHERE primakey=1;
MySql 5.6.26をインストールすると、キーはNULLに対応せず、エラーが発生します。
#1048 - Column 'primakey' cannot be null
したがって、一時テーブルを作成した後、主キーをNULL可能に変更します。
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;
私はこれをしなければならなかった、これは私の手動の解決策でした:
PRIMARYフィールドが何であるかわからない場合は、phpmyadminページを振り返り、'Structure'タブをクリックしてページの下の'Indexes'の下に、どの'Field'に'Keyname' value 'があるかが表示されますPRIMARY '。
長い道のりのようなものですが、マークアップを処理したくない場合は、1行だけを複製する必要があります。
このサイトでオンラインで見つけた回答を次に示します。上記の方法を説明します 1 ページの下部に回答があります。基本的には、メモリに保持されている一時テーブルにコピーする行をコピーします。次に、更新を使用して主キー番号を変更します。その後、ターゲットテーブルに再挿入します。次に、テーブルをドロップします。
これはそのためのコードです:
CREATE TEMPORARY TABLE
rescueteam
ENGINE = MEMORY SELECT * FROMfitnessreport4
WHERE rID = 1;#1行が影響を受けました。 UPDATErescueteam
SET rID = Null WHERE rID = 1;#1行が影響を受けました。INSERTINTOfitnessreport4
SELECT * FROMrescueteam
;#1行が影響を受けました。 DROP TABLErescueteam
#MySQLは空の結果セットを返しました(つまり、ゼロ
列)。
一時テーブルrescueteamを作成しました。元のテーブルfitnessreport4から行をコピーしました。その後、一時テーブルの行の主キーをnullに設定して、キーの重複エラーを発生させることなく元のテーブルにコピーできるようにします。昨日の夜、このコードを試してみましたが、うまくいきました。
ネクロポストで申し訳ありませんが、これは私がグーグルで見つけたものです。
まず、MySQLではなくSQL Serverを使用していますが、同様に動作するはずです。私はレナード・チャリスのソリューションを使用しましたが、それは最も単純でニーズを満たしていましたが、これには問題があります-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
これはMySQLでも同様に機能すると思いますが、これをテストすることはできません。
Kohaデータベースで使用して、バーコード列に 'C'プレフィックスを持つ重複アイテムを挿入しました:
INSERT INTO items (`biblionumber`, `biblioitemnumber`, `barcode`, `dateaccessioned` ) SELECT `biblionumber`, `biblioitemnumber`, CONCAT('C',`barcode`), `dateaccessioned` FROM `items` WHERE barcode='14832';
テーブルを作成する
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 INTO `sample_table`
VALUES(NULL, 'sample name', 1, 2);
上記の行挿入を複製
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;
テスト
SELECT * FROM `sample_table`;
私はそれが古い質問であることを知っていますが、別の解決策があります:
これは、主キーが自動インクリメントであると仮定して、メインテーブルの行を複製し、リンクテーブルデータのコピーを新しいメインテーブルIDで作成します。
列名を取得するための他のオプション:
-tablename
から列を表示; (列名:フィールド)
-DESCRIBE tablename
(列名:フィールド)
-SELECT column_name FROM information_schema.columns WHERE table_name = 'tablename'(列名: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は確かに正しい軌道に乗っていました。ただし、ALTER TABLEは実行しないでください。一時テーブルの自動インクリメントフィールドをNULLに設定するだけです。これによりエラーが発生しますが、一時テーブル内のすべてのフィールドの次のINSERTが発生し、NULL自動フィールドは一意の値を取得します。