Làm thế nào để bạn sao chép một bản ghi trong bảng SQL nhưng trao đổi id duy nhất của hàng mới?


123

Câu hỏi này gần với những gì tôi cần, nhưng kịch bản của tôi hơi khác. Bảng nguồn và bảng đích giống nhau và khóa chính là một định danh duy nhất (hướng dẫn). Khi tôi thử điều này:

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

Tôi rõ ràng nhận được một vi phạm ràng buộc khóa chính, vì tôi đang cố sao chép trên khóa chính. Trên thực tế, tôi không muốn sao chép khóa chính. Thay vào đó, tôi muốn tạo một cái mới. Ngoài ra, tôi muốn sao chép có chọn lọc trên các trường nhất định và để trống các trường khác. Để làm cho vấn đề phức tạp hơn, tôi cần lấy khóa chính của bản ghi gốc và chèn nó vào một trường khác trong bản sao (trường BeforeId).

Tôi chắc chắn có một giải pháp dễ dàng cho vấn đề này, tôi chỉ không biết đủ TSQL để biết nó là gì.

Câu trả lời:


186

Thử cái này:


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

Bất kỳ trường nào không được chỉ định sẽ nhận giá trị mặc định của chúng (thường là NULL khi không được xác định).


2
Tuyệt vời. Làm việc như người ở. Nó đã quá rõ ràng khi bạn viết nó ra. Cảm ơn!!
Kilhoffer

1
Điều này sẽ hoạt động nếu bạn có một vài cột. Nếu bạn đã nói 20 hoặc 30 cột, bạn vẫn có thể sử dụng phương pháp này, nhưng nó sẽ gây nản chí. Ngoài ra, mỗi khi bạn thêm một cột và muốn sao chép dữ liệu đó, cần thêm cột vào tập lệnh này. Tốt nhất là tạo động chèn bằng bảng sys.
Jeyara

93

Ok, tôi biết rằng đó là một vấn đề cũ nhưng dù sao tôi cũng đăng câu trả lời của mình.

Tôi thích giải pháp này. Tôi chỉ phải xác định (các) cột danh tính.

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" -column là cột nhận dạng và đó là cột duy nhất tôi phải chỉ định. Dù sao nó cũng tốt hơn so với cách khác. :-)

Tôi sử dụng máy chủ SQL. Bạn có thể muốn sử dụng " CREATE TABLE" và " UPDATE TABLE" ở hàng 1 và 2. Hmm, tôi thấy rằng tôi đã không thực sự đưa ra câu trả lời mà anh ấy muốn. Anh cũng muốn sao chép id sang cột khác. Nhưng giải pháp này là tốt để tạo một bản sao với id tự động mới.

Tôi chỉnh sửa giải pháp của mình với các idéas từ Michael Dibbets.

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;

Bạn có thể thả nhiều hơn một cột bằng cách tách chúng bằng dấu ",". Id: nên được thay thế bằng id của hàng bạn muốn sao chép. MyDatabase, MyTable và IndexField nên được thay thế bằng tên của bạn (tất nhiên).


1
Điều này thật khó khăn, làm thế nào bạn có thể chắc chắn rằng bạn đang sao chép đúng id vào hàng đúng trong suốt INSERT INTO trong dòng 3?
Erno

Cột id là một cột danh tính (trong bảng của tôi) vì vậy tôi không quan tâm đến giá trị. Tôi chỉ muốn một bản ghi mới giữ các giá trị giống như bản ghi "cũ".
Jonas

9
TempTable, nó sẽ tốt hơn để sử dụng #TempTable, vì vậy nó là một bảng tạm thời thực sự?
Jess

3
Tôi đang sử dụng định dạng 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;này theo cách sau Tôi biết rằng nó sẽ được dọn sạch càng sớm càng tốt mà không có bất kỳ sự chậm trễ nào trong việc ghi tệp gián đoạn vào đĩa.
Tschallacka

3
Bạn cũng có thể sử dụng $identitynếu bạn không muốn mã cứng tên cột danh tính của mình
Yếu tố huyền bí

12

Tôi đoán bạn đang cố gắng tránh viết ra tất cả các tên cột. Nếu bạn đang sử dụng SQL Management Studio, bạn có thể dễ dàng nhấp chuột phải vào bảng và Tập lệnh dưới dạng Chèn .. thì bạn có thể tìm kiếm xung quanh với đầu ra đó để tạo truy vấn của mình.


10

Chỉ định tất cả các trường trừ trường ID của bạn.

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

6

Tôi có cùng một vấn đề khi tôi muốn một tập lệnh duy nhất hoạt động với một bảng có các cột được thêm theo định kỳ bởi các nhà phát triển khác. Không chỉ vậy, nhưng tôi đang hỗ trợ nhiều phiên bản cơ sở dữ liệu khác nhau vì khách hàng có thể không cập nhật với phiên bản hiện tại.

Tôi lấy giải pháp của Jonas và sửa đổi nó một chút. Điều này cho phép tôi tạo một bản sao của hàng và sau đó thay đổi khóa chính trước khi thêm lại vào bảng nguồn ban đầu. Điều này cũng thực sự tiện dụng khi làm việc với các bảng không cho phép các giá trị NULL trong các cột và bạn không muốn phải chỉ định từng tên cột trong INSERT.

Mã này sao chép hàng cho 'ABC' thành 'XYZ'

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

Một khi bạn đã hoàn thành việc thả bảng tạm thời.

DROP TABLE #TempRow;

4

Tôi biết câu trả lời của tôi là muộn cho bữa tiệc. Nhưng cách tôi giải quyết hơi khác so với tất cả các câu trả lời.

Tôi đã có một tình huống, tôi cần sao chép một hàng trong một bảng trừ vài cột. Những người đó sẽ có những giá trị mới. Quá trình này sẽ hỗ trợ tự động cho các thay đổi trong tương lai của bảng. Điều này ngụ ý, sao chép bản ghi mà không chỉ định bất kỳ tên cột.

Cách tiếp cận của tôi là,

  1. Truy vấn Sys.Columns để lấy danh sách đầy đủ các cột cho bảng và bao gồm tên của các cột cần bỏ qua trong mệnh đề where.
  2. Chuyển đổi nó thành CSV dưới dạng tên cột.
  3. Xây dựng Chọn ... Chèn vào tập lệnh dựa trên điều này.


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)


2
insert into MyTable (uniqueId, column1, column2, referencedUniqueId)
select NewGuid(), // don't know this syntax, sorry
  column1,
  column2,
  uniqueId,
from MyTable where uniqueId = @Id

1

Nếu "khóa" là trường PK của bạn và nó tự động.

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

nó sẽ tạo một bản ghi mới, sao chép trường1 và trường2 từ bản ghi gốc


1

Bảng của tôi có 100 trường và tôi cần một truy vấn để chỉ hoạt động. Bây giờ tôi có thể chuyển đổi bất kỳ số lượng trường nào với một số logic điều kiện cơ bản và không phải lo lắng về vị trí thứ tự của nó.

  1. Thay thế tên bảng dưới đây bằng tên bảng của bạn

    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. Thay thế tên trường danh tính ban đầu bằng tên trường PK của bạn

    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. Thay thế tên bảng một lần nữa (cả tên bảng mục tiêu và tên bảng nguồn); chỉnh sửa wheređiều kiện của bạn

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

0

Bạn có thể làm như thế này:

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

Ở đó thay vì 112, bạn nên đặt một số id tối đa trong bảng DENI / FRIEN01P.


0

Đây là cách tôi đã thực hiện bằng cách sử dụng ASP classic và không thể làm cho nó hoạt động với các câu trả lời ở trên và tôi muốn có thể sao chép một sản phẩm trong hệ thống của chúng tôi sang một sản phẩm mới và cần nó có thể hoạt động ngay cả khi chúng tôi thêm nhiều cột vào bảng

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")

Tôi không nghĩ bạn cần phát hành 5 lệnh SQL riêng biệt để hoàn thành việc này. Và ngoài ra, bạn xác định ai trong lệnh thứ 2, id sản phẩm đó phải là 34567?
Jeyara

34567 chỉ là một ví dụ. Bạn có thể đặt nó thành một biến hoặc bất cứ điều gì bạn muốn. Nếu bạn có cách tốt hơn để làm điều này trong ASP Classic, hãy cho tôi biết. :)
Daniel Nordh

bạn có thể viết một Proc được lưu trữ để chạy tất cả những thứ này trong một dòng. Ngoài ra, thường PK được sử dụng làm giá trị tăng tự động. Vì vậy, giao cho chính mình không phải là một ý tưởng tốt.
Jeyara

Làm thế nào bạn sẽ viết thủ tục nói? Vui lòng làm sáng tỏ cho tôi. PK? Nếu bạn có nghĩa là ID bài viết, trong hệ thống của chúng tôi, chúng tôi sử dụng ID bài viết dựa trên cửa hàng chúng tôi bán chúng. Ví dụ: cửa hàng đồ chơi của chúng tôi có số bài viết bắt đầu bằng 30 và cửa hàng thể thao của chúng tôi bắt đầu bằng 60. Ngoài ra, chúng tôi tiết kiệm không gian để nếu chúng tôi lấy một màu mới, ví dụ, chúng ta có thể có ID bài viết bên cạnh các loại khác cùng loại. Như đã nói, đây là giải pháp của tôi hoạt động trong hệ thống của chúng tôi. Cách bạn đặt biến không quan trọng và hầu hết các lập trình viên sẽ hiểu những gì hoạt động cho họ và hệ thống của họ.
Daniel Nordh

PK là viết tắt của khóa chính. Trong trường hợp của bạn, đó là '12345'. Xem stackoverflow.com/questions/21561657/ cấp để biết cách sử dụng Proc được lưu trữ trong Classic ASP nếu bạn không biết cách. Để thực hiện việc này, di chuyển tất cả những người vào một Proc được lưu trữ và chuyển '12345' của bạn làm tham số. Cách bạn làm sẽ hoạt động nhưng Tập lệnh được tham số hóa được khuyến nghị hiện nay.
Jeyara 17/03/19
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.