Как скопировать запись в таблицу SQL, но поменять уникальный идентификатор новой строки?


123

Этот вопрос близок к тому, что мне нужно, но мой сценарий немного отличается. Исходная таблица и таблица назначения одинаковы, а первичный ключ - это уникальный идентификатор (guid). Когда я пробую это:

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

Я, очевидно, получаю нарушение ограничения первичного ключа, поскольку пытаюсь скопировать первичный ключ. На самом деле я вообще не хочу копировать первичный ключ. Скорее хочу создать новый. Кроме того, я хотел бы выборочно скопировать определенные поля, а остальные оставить пустыми. Чтобы усложнить ситуацию, мне нужно взять первичный ключ исходной записи и вставить его в другое поле копии (поле PreviousId).

Я уверен, что есть простое решение, я просто не знаю достаточно TSQL, чтобы понять, что это такое.

Ответы:


186

Попробуй это:


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

Любые неуказанные поля должны получить свое значение по умолчанию (которое обычно равно NULL, если не определено).


2
Потрясающие. Работал как шарм. Это было так очевидно, когда ты это написал. Спасибо!!
Килхоффер,

1
Это будет работать, если у вас мало столбцов. Если у вас есть 20 или 30 столбцов, вы все равно можете использовать этот метод, но это будет сложно. Кроме того, каждый раз, когда вы добавляете столбец и хотите скопировать эти данные, необходимо добавить столбец в этот скрипт. Лучше всего генерировать вставку динамически, используя таблицы sys.
Jeyara

93

Хорошо, я знаю, что это старая проблема, но я все равно отправляю свой ответ.

Мне нравится это решение. Мне нужно только указать столбец (-ы) идентичности.

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» - это столбец идентификации, и это единственный столбец, который мне нужно указать. В любом случае это лучше, чем наоборот. :-)

Использую SQL Server. Вы можете использовать " CREATE TABLE" и " UPDATE TABLE" в строках 1 и 2. Хм, я увидел, что на самом деле не дал того ответа, который он хотел. Он также хотел скопировать идентификатор в другой столбец. Но это решение подходит для создания копии с новым авто-идентификатором.

Я редактирую свое решение с использованием идей Майкла Диббетса.

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 следует подставить идентификатор строки, которую вы хотите скопировать. MyDatabase, MyTable и IndexField следует заменить своими именами (конечно).


1
Это сложно, как вы можете быть уверены, что копируете правильный идентификатор в правильную строку во время INSERT INTO в строке 3?
Erno

Идентификационный столбец - это столбец идентификаторов (в моей таблице), поэтому меня не волнует значение. Я просто хочу, чтобы новая запись содержала те же значения, что и «старая».
Jonas

9
Ибо TempTable, не лучше ли использовать #TempTable, так что это настоящая временная таблица?
Джесс

3
Я использую это в следующем формате. use MyDatabase; SELECT * INTO #TempTable FROM [TABLE] WHERE [indexfield] = :id; ALTER TABLE #TempTable DROP COLUMN [indexfield]; INSERT INTO [TABLE] SELECT * FROM #TempTable; DROP TABLE #TempTable;Таким образом, я знаю, что он будет очищен как можно скорее без каких-либо задержек при записи временного файла на диск.
Tschallacka

3
Вы также можете использовать, $identityесли не хотите жестко кодировать имя столбца идентификатора
Factor Mystic

12

Я предполагаю, что вы пытаетесь избежать записи всех имен столбцов. Если вы используете SQL Management Studio, вы можете легко щелкнуть правой кнопкой мыши по таблице и «Сценарий как вставка» ... тогда вы можете возиться с этим выводом для создания своего запроса.


10

Укажите все поля, кроме поля вашего идентификатора.

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

6

У меня такая же проблема, когда я хочу, чтобы один скрипт работал с таблицей, в которую периодически добавляются столбцы другими разработчиками. Более того, я поддерживаю множество различных версий нашей базы данных, так как не все клиенты могут быть в курсе текущей версии.

Я взял решение Джонаса и немного изменил его. Это позволяет мне сделать копию строки, а затем изменить первичный ключ перед добавлением его обратно в исходную исходную таблицу. Это также очень удобно для работы с таблицами, которые не допускают значений 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

Я знаю, что мой ответ опаздывает на вечеринку. Но способ, которым я решил, немного отличается от всех ответов.

У меня была ситуация, мне нужно клонировать строку в таблице, кроме нескольких столбцов. У этих немногих появятся новые ценности. Этот процесс должен автоматически поддерживаться для будущих изменений в таблице. Это подразумевает клонирование записи без указания имен столбцов.

Мой подход заключается в том,

  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

Если «ключ» - это ваше поле PK, и оно является автономным.

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

он сгенерирует новую запись, скопировав field1 и field2 из исходной записи


1

В моей таблице 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. Замените исходное имя поля идентификатора своим именем поля 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)

0

Сделать можно так:

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

Там вместо 112 в таблицу DENI / FRIEN01P нужно поставить номер максимального id.


0

Вот как я сделал это с помощью классического ASP и не смог заставить его работать с приведенными выше ответами, и я хотел иметь возможность скопировать продукт в нашей системе на новый 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")

Я не думаю, что вам нужно выполнить 5 отдельных команд SQL, чтобы завершить это. А также, кого вы определяете во второй команде, этот идентификатор продукта должен быть 34567?
Jeyara

34567 - это просто пример. Вы можете установить его в переменную или что угодно. Если у вас есть лучший способ сделать это в ASP Classic, дайте мне знать. :)
Daniel Nordh

вы можете написать сохраненный процесс, чтобы запускать все это в одной строке. Кроме того, обычно PK было значением автоматического увеличения. Так что назначать себя - не лучшая идея.
Jeyara

Как бы вы написали указанную процедуру? Пожалуйста, просветите меня. PK? Если вы имеете в виду идентификаторы статей, в нашей системе мы используем идентификаторы статей в зависимости от того, в каком магазине мы их продаем. Например, в нашем магазине игрушек все номера товаров начинаются с 30, а в нашем спортивном магазине - с 60. Кроме того, мы экономим места, чтобы, если мы получить новый цвет, например, мы можем иметь идентификатор статьи рядом с другими такого же типа. Как уже было сказано, это было мое решение, которое работает в нашей системе. То, как вы устанавливаете переменные, не так важно, и большинство программистов поймут, что работает для них и их системы.
Daniel Nordh

PK означает первичный ключ. В вашем случае это «12345». Видеть Stackoverflow.com/questions/21561657/…, чтобы узнать, как использовать сохраненную процедуру в классическом ASP, если вы не знаете, как это сделать. Для этого переместите все это в одну сохраненную процедуру и передайте свой «12345» в качестве параметра. То, как вы это делаете, будет работать, но в наши дни рекомендуются параметризованные скрипты.
Jeyara
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.