MySQLの行をコピーして、自動インクリメントフィールドを持つ同じテーブルに挿入する方法は?


233

MySQLの私にして行をコピーしようとしています自動インクリメント column ID=1および挿入で新しい行として同じテーブルにデータをcolumn ID=2

これを単一のクエリでどのように実行できますか?

回答:


351

使用INSERT ... SELECT

insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where id = 1

c1, c2, ...を除くすべての列idです。idof 2で明示的に挿入する場合は、それをINSERT列リストとSELECTに含めます。

insert into your_table (id, c1, c2, ...)
select 2, c1, c2, ...
from your_table
where id = 1

idもちろん、2番目のケースでは2の重複の可能性に注意する必要があります。


1
次に、INFORMATION_SCHEMAを使用して列の名前をプログラムで取得できます。サブクエリおよび一部の文字列関数として実行できるかどうかは疑問です。
うーん

1
@Yzmir:動的SQLを使用する必要があり、通常はストアドプロシージャの構築が必要になります。とにかく便利な列名のリストを用意する必要がある場合、それよりも問題が多いようです。
muが短すぎる

6
同意します...私の手順では、ストアドプロシージャを実行すると、元に戻すことはできません。今はそのデータベースと結婚していて、変更したいときはいつでもコストが増えるだけです。
Yzmir Ramirez、2012

11
@YzmirRamirez、あなたは結婚が本質的に悪いことのように聞こえるようにします。:)
Falken教授2013

1
他のすべてのコピーされたフィールドを含む列に1つのカスタム値を追加するにはどうすればよいですか?
Manish Kumar

49

IMO、最善の方法は、SQLステートメントを使用してその行をコピーするだけで、同時に必要な列と変更したい列のみを参照することです。

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;

av8n.com-SQLレコードを複製する方法も参照してください

利点:

  • SQLステートメント2には、クローン作成プロセス中に変更する必要があるフィールドのみが記載されています。彼らは他の分野について知らない、または気にしない。他のフィールドは、変更されずにそのままライドに進みます。これにより、SQLステートメントの作成、読み取り、保守、および拡張が容易になります。
  • 通常のMySQLステートメントのみが使用されます。他のツールやプログラミング言語は必要ありません。
  • 完全に正しいレコードがyour_table1つのアトミック操作で挿入されます。

3
このすばらしいトリック(私は気に入ったが、私には機能しなかった)が、TEXT / VARCHAR列を含むテーブルでは機能しないことを示しています。私はそれを試して得ました:(1163):使用されているテーブルタイプはBLOB / TEXT列をサポートしていません。もちろん、MySQLでの使用は非常に制限されます。将来的には、これらの制限が解除されるか、他のdbシステムで機能する可能性がありますが、現時点では実際には制限されています。
Juergen 2013年

一時テーブルを上手に使うのが本当に好きです。大量の列があるテーブルにとても便利です!
Lasma

1
見栄えは良いですが、MySQLで最初のクエリを実行すると、が表示されますError Code: 1113. A table must have at least 1 column
物理的な

3
多くの列に最適な回答です。しかしSET id=NULL、エラーが発生する可能性がありますColumn 'id' cannot be null。置き換える必要がありますUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
モダー

1
@physicalattraction最初の2行が1つのステートメントであることを確認する必要があります。
Samuurai 2017年

16

テーブルがあると言いますuser(id, user_name, user_email)

次のクエリを使用できます。

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)

29
INSERTを使用するときは常に列名を指定する必要があります。そうしないと、スキーマが変更されたときに奇妙で興味深いバグが発生します。
muが短すぎる

2
奇妙で面白いです。:D
sparkyShorts

sqliteでは機能しません。 Result: near "SELECT": syntax error
kyb

10

これは役立ち、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;

これは他の回答よりもどのように優れていますか?
Smar 2016年

3
100個のフィールドを持つテーブルがあれば、かなり良いと思います。それは失敗しますIDにNOT NULL制約があるかもしれません除き
ロイック・フォーレ-ラクロワ

エラーコード:1136。列数が行1の値数と一致しません
Oleksii Kyslytsyn

数百の列を持つテーブルがある場合、これははるかに優れています。
タイラーS.レーパー

何年も前に、これは普通のことを言っていませんか?
ToolmakerSteve

7

列に名前を付ける必要がない迅速でクリーンなソリューションの場合は、https//stackoverflow.com/a/23964285/292677の説明に従って準備されたステートメントを使用できます

これを頻繁に実行できるように複雑なソリューションが必要な場合は、次の手順を使用できます。

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

あなたはそれを実行することができます:

CALL duplicateRows('database', 'table', 'WHERE condition = optional', 'omit_columns_optional');

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

免責事項:この解決策は、多くの場合、多くのテーブルで行を繰り返し複製する人のみを対象としています。悪意のあるユーザーの手に渡ると危険です。


3

自動インクリメントする列の値として「0」を渡すこともできます。レコードが作成されるときに正しい値が使用されます。これは一時テーブルよりもはるかに簡単です。

ソース: MySQLでの行のコピー (TRiGによる2番目のコメント、Loreによる最初のソリューションへのコメントを参照)


1
この方法は、NULLが受け入れられない場合、新しいMySQLバージョンで機能します。
エラー

3

ここにはたくさんの素晴らしい答えがあります。以下は、開発中の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

MariaDB / MySQLの現在のバージョンでは、id = nullを設定すると#1048が返されます-列「id」はnullにできません。
シェルペペレイラ

2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

3
これはここの他の答えよりどのように優れていますか?
Smar 2016年

1
@smar imo理解しやすくなりました
Satbir Kira

2

MySQL Workbenchを使用できる場合は、行を右クリックして[行をコピー]を選択し、次に空の行を右クリックして[行を貼り付け]を選択し、IDを変更して、 「適用」をクリックします。

行をコピーします。

ここに画像の説明を入力してください

コピーした行を空白行に貼り付けます。

ここに画像の説明を入力してください

IDを変更します。

ここに画像の説明を入力してください

適用:

ここに画像の説明を入力してください


0

同じ機能を探していましたが、MySQLを使用していません。もちろん主キー(id)を除くすべてのフィールドをコピーしたいと思いました。これはワンショットクエリであり、スクリプトやコードでは使用されません。

私はPL / SQLで自分の道を見つけましたが、他のSQL IDEでうまくいくと確信しています。基本的な

SELECT * 
FROM mytable 
WHERE id=42;

次に、それをSQLファイルにエクスポートします。

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (1, 2, 3, ..., 42);

私はそれを編集して使用しました:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);

0

私はムーが短すぎるもののバリエーションを投稿する傾向があります:

INSERT INTO something_log
SELECT NULL, s.*
FROM something AS s
WHERE s.id = 1;

テーブルに同一のフィールドがある限り(ログテーブルの自動インクリメントを除く)、これは適切に機能します。

私は可能な限りストアドプロシージャを使用するため(データベースに精通していない他のプログラマーの作業を楽にするため)、これにより、新しいフィールドをテーブルに追加するたびに手順に戻って更新しなければならないという問題が解決します。

また、テーブルに新しいフィールドを追加すると、データベースクエリを更新する必要なく、ログテーブルにすぐに表示されるようになります(もちろん、フィールドを明示的に設定している場合を除きます)。

警告:両方のテーブルに新しいフィールドを同時に追加して、フィールドの順序が同じになるようにする必要があります。そうしないと、奇妙なバグが発生し始めます。あなたがデータベースインターフェースを書く唯一の人であり、あなたが非常に注意しているなら、これはうまくいきます。それ以外の場合は、すべてのフィールドに名前を付けます。

注:考え直してください。ソロプロジェクトで作業している場合を除いて、他の人がすべてのフィールド名を明示的にリストすることに専念し、スキーマの変更に応じてログステートメントを更新することはありません。このショートカットは、おそらくそれが引き起こす長期的な頭痛の種には値しません...特に本番システムでは。


0
INSERT INTO `dbMyDataBase`.`tblMyTable` 
(
    `IdAutoincrement`、 
    `Column2`、 
    `Column3`、 
    `列4` 
) 

選択する 
    ヌル、  
    `Column2`、 
    `Column3`、 
    'CustomValue' AS列4 
FROM `dbMyDataBase`.`tblMyTable` 
WHERE `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /

3
さらに詳細な説明を追加してみてください。または、これが他の回答にどのように展開されるかを確認してください
Azsgy

-1

SQLする行をダンプし、生成されたSQLを使用して、ID列を差し引いてインポートします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.