web-dev-qa-db-ja.com

SQLテーブルのレコードをコピーし、新しい行の一意のIDを交換するにはどうすればよいですか?

この質問 は必要なものに近づいていますが、私のシナリオは少し異なります。ソース表と宛先表は同じであり、主キーはuniqueidentifier(guid)です。私がこれを試すとき:

insert into MyTable
    select * from MyTable where uniqueId = @Id;

主キーをコピーしようとしているため、明らかに主キー制約違反が発生します。実際、主キーをコピーしたくありません。むしろ、新しいものを作りたいです。さらに、特定のフィールドを選択的にコピーし、他のフィールドをヌルのままにしておきたいと思います。問題をより複雑にするために、元のレコードの主キーを取得し、それをコピーの別のフィールド(PreviousIdフィールド)に挿入する必要があります。

これには簡単な解決策があると確信しています。TSQLが何であるかを知るのに十分なTSQLを知りません。

114
Kilhoffer

これを試して:


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

指定されていないフィールドは、デフォルト値(定義されていない場合は通常NULL)を受け取る必要があります。

176
AaronSieb

OK、それは古い問題であることは知っていますが、とにかく答えを投稿します。

私はこの解決策が好きです。 ID列を指定するだけです。

SELECT * INTO TempTable FROM MyTable_T WHERE id = 1;
ALTER TABLE TempTable DROP COLUMN id;
INSERT INTO MyTable_T SELECT * FROM TempTable;
DROP TABLE TempTable;

「id」列はID列であり、指定する必要がある唯一の列です。とにかく他の方法よりも優れています。 :-)

SQL Serverを使用しています。行1と2で「CREATE TABLE」と「UPDATE TABLE」を使用したい場合があります。彼はIDを別の列にもコピーしたかった。しかし、このソリューションは、新しい自動IDでコピーを作成するのに適しています。

Michael Dibbetsのidéasを使用してソリューションを編集します。

use MyDatabase; 
SELECT * INTO #TempTable FROM [MyTable] WHERE [IndexField] = :id;
ALTER TABLE #TempTable DROP COLUMN [IndexField]; 
INSERT INTO [MyTable] SELECT * FROM #TempTable; 
DROP TABLE #TempTable;

「、」で区切ることにより、複数の列をドロップできます。 :idは、コピーする行のIDに置き換える必要があります。 (もちろん)MyDatabase、MyTable、IndexFieldは自分の名前に置き換える必要があります。

85
Jonas

すべての列名を書き出すのを避けようとしているのではないでしょうか。 SQL Management Studioを使用している場合は、テーブルを簡単に右クリックし、[挿入としてスクリプト]をクリックしてから、その出力をいじってクエリを作成できます。

12
Matt Hinze

IDフィールド以外のすべてのフィールドを指定します。

INSERT INTO MyTable (FIELD2, FIELD3, ..., FIELD529, PreviousId)
SELECT FIELD2, NULL, ..., FIELD529, FIELD1
FROM MyTable
WHERE FIELD1 = @Id;
10
Scott Bevington

他の開発者によって定期的に列が追加されたテーブルで単一のスクリプトを使用したいという同じ問題があります。それだけでなく、私たちのデータベースの多くの異なるバージョンをサポートしています。顧客はすべて最新バージョンではないかもしれません。

Jonasが解決策を取り、それを少し修正しました。これにより、行のコピーを作成し、主キーを変更してから元のソーステーブルに追加することができます。これは、列にNULL値を許可しないテーブルを操作する場合にも非常に便利で、INSERTで各列名を指定する必要はありません。

このコードは、「ABC」の行を「XYZ」にコピーします

SELECT * INTO #TempRow FROM SourceTable WHERE KeyColumn = 'ABC';
UPDATE #TempRow SET KeyColumn = 'XYZ';
INSERT INTO SourceTable SELECT * FROM #TempRow;
DELETE #TempRow;

ドロップが完了したら、一時テーブルを削除します。

DROP TABLE #TempRow;
4
TonyT
insert into MyTable (uniqueId, column1, column2, referencedUniqueId)
select NewGuid(), // don't know this syntax, sorry
  column1,
  column2,
  uniqueId,
from MyTable where uniqueId = @Id
2

「キー」がPKフィールドであり、それが自動数値である場合。

insert into MyTable (field1, field2, field3, parentkey)
select field1, field2, null, key from MyTable where uniqueId = @Id

元のレコードからfield1とfield2をコピーして、新しいレコードを生成します

1

私の答えはパーティーに遅れていることを知っています。しかし、私が解決した方法は、すべての答えとは少し異なります。

いくつかの列を除いて、テーブルの行を複製する必要がある状況がありました。それらのいくつかには新しい価値があります。このプロセスは、テーブルに対する将来の変更を自動的にサポートする必要があります。これは、列名を指定せずにレコードを複製することを意味します。

私のアプローチは、

  1. Sys.Columnsをクエリして、テーブルの列の完全なリストを取得し、where句でスキップする列の名前を含めます。
  2. それを列名としてCSVに変換します。
  3. Build Select ...これに基づいてスクリプトに挿入します。

declare @columnsToCopyValues varchar(max), @query varchar(max)
SET @columnsToCopyValues = ''


--Get all the columns execpt Identity columns and Other columns to be excluded. Say IndentityColumn, Column1, Column2 Select @columnsToCopyValues = @columnsToCopyValues + [name] + ', ' from sys.columns c where c.object_id = OBJECT_ID('YourTableName') and name not in ('IndentityColumn','Column1','Column2') Select @columnsToCopyValues = SUBSTRING(@columnsToCopyValues, 0, LEN(@columnsToCopyValues)) print @columnsToCopyValues


Select @query = CONCAT('insert into YourTableName (',@columnsToCopyValues,', Column1, Column2) select ', @columnsToCopyValues, ',''Value1'',''Value2'',', ' from YourTableName where IndentityColumn =''' , @searchVariable,'''')


print @query exec (@query)
1
Jeyara

私のテーブルには100個のフィールドがあり、機能するためにはクエリが必要でした。これで、基本的な条件付きロジックを使用して任意の数のフィールドを切り替えることができ、順序の位置について心配する必要はありません。

  1. 以下のテーブル名をテーブル名に置き換えます

    SQLcolums = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE (TABLE_NAME = 'TABLE-NAME')"
    
    Set GetColumns = Conn.Execute(SQLcolums)
    Do WHILE not GetColumns.eof
    
    colName = GetColumns("COLUMN_NAME")
    
  2. 元のIDフィールド名をPKフィールド名に置き換えます

    IF colName = "ORIGINAL-IDENTITY-FIELD-NAME" THEN ' ASSUMING THAT YOUR PRIMARY KEY IS THE FIRST FIELD DONT WORRY ABOUT COMMAS AND SPACES
        columnListSOURCE = colName 
        columnListTARGET = "[PreviousId field name]"
    ELSE
        columnListSOURCE = columnListSOURCE & colName
        columnListTARGET = columnListTARGET & colName
    END IF
    
    GetColumns.movenext
    
    loop
    
    GetColumns.close    
    
  3. テーブル名を再度置き換えます(ターゲットテーブル名とソーステーブル名の両方)。 where条件を編集します

    SQL = "INSERT INTO TARGET-TABLE-NAME (" & columnListTARGET & ") SELECT " & columnListSOURCE & " FROM SOURCE-TABLE-NAME WHERE (FIELDNAME = FIELDVALUE)" 
    Conn.Execute(SQL)
    
1
Rit Man

このようにすることができます:

INSERT INTO DENI/FRIEN01P 
SELECT 
   RCRDID+112,
   PROFESION,
   NAME,
   SURNAME,
   AGE, 
   RCRDTYP, 
   RCRDLCU, 
   RCRDLCT, 
   RCRDLCD 
FROM 
   FRIEN01P      

112ではなく、テーブルDENI/FRIEN01Pに最大IDの番号を入力する必要があります。

0
Denis Kutlubaev

ASP classicを使用してそれを実行した方法を次に示します。上記の回答ではうまく動作せず、システム内の製品を新しいproduct_idにコピーできるようにしたかったのです。テーブルに列を追加しても機能します。

Cn.Execute("CREATE TEMPORARY TABLE temprow AS SELECT * FROM product WHERE product_id = '12345'")
Cn.Execute("UPDATE temprow SET product_id = '34567'")
Cn.Execute("INSERT INTO product SELECT * FROM temprow")
Cn.Execute("DELETE temprow")
Cn.Execute("DROP TABLE temprow")
0
Daniel Nordh