web-dev-qa-db-ja.com

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

テーブルEgTableがあります。私がやろうとしているのは、オートインクリメント列ID = 1の行をコピーして、行と列ID = 2の同じテーブルにデータを挿入することです。

MySqlを使うこれを1回のクエリで実行する方法を教えてください。

193
Navdroid

INSERT ... SELECTを使用してください。

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

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

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

2番目のケースでは、2のidが重複している可能性があることに注意する必要があります。

296
mu is too short

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ステートメントのみが使用されます。他のツールやプログラミング言語は必要ありません。
  • 1回のアトミック操作で、完全に正しいレコードがyour_tableに挿入されます。
42
parvus

テーブルがuser(id, user_name, user_email)だとしましょう。

あなたはこのクエリを使用することができます:

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

これにより、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;
9
Petr Hladík

列に名前を付ける必要のない迅速でクリーンな解決策としては、ここで説明するように準備済みステートメントを使用できます。 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

免責事項:この解決策は、多くの場合、多くの場合、繰り返し行を複製することになる人のためのものです。悪意のあるユーザーの手に渡ると危険な場合があります。

7
curmil

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

出典: MySQLで行をコピーする (TRiGによる2番目のコメント、Loreによる1番目の解決策への参照)

2
Mark Pruce
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;
2
IR.Programmer

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

私はmuが短すぎる投稿のバリエーションを使用する傾向があります。

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

テーブルが同じフィールドを持っている限り(ログテーブルの自動インクリメントを除く)、これはうまく機能します。

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

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

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

注: /考え直してください。単独のプロジェクトで作業しているのでなければ、他の人が作業していると確信している場合を除き、すべてのフィールド名を明示的にリストし、スキーマを変更してログステートメントを更新します。この近道はおそらくそれが引き起こす可能性がある長期にわたる頭痛の種にはならないでしょう…特に本番システムでは。

0
Privateer

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

0
Claire

同じ機能を探していましたが、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
SabineA
 INSERT INTO 'dbMyDataBase`.`tblMyTable` 
(
 IdAutoincrement`、
 `Column2`、
` Column3`、[.____ [Column4] 
)
 
 SELECT 
 NULL、
 `Column2`、
` Column3`、[.____ 。[CustomValue] AS Column4 
 FROM `dbMyDataBase`.`tblMyTable` 
 WHERE` tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
; 
/* mySQL 5.6 */
0