คุณจะคัดลอกระเบียนในตาราง SQL ได้อย่างไร แต่จะสลับ id เฉพาะของแถวใหม่


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
น่ากลัว ทำงานอย่างมีเสน่ห์ มันชัดเจนมากเมื่อคุณเขียนมันออกมา ขอบคุณ !!
Kilhoffer

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 อืมฉันเห็นว่าฉันไม่ได้ให้คำตอบที่เขาต้องการจริงๆ เขาต้องการคัดลอกรหัสไปยังคอลัมน์อื่นด้วย แต่วิธีนี้เหมาะสำหรับการทำสำเนาด้วยรหัสอัตโนมัติใหม่

ฉันแก้ไขโซลูชันของฉันด้วยไอเดียจาก 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;

คุณสามารถวางคอลัมน์ได้มากกว่าหนึ่งคอลัมน์โดยคั่นด้วย "," ควรแทนที่: id ด้วย id ของแถวที่คุณต้องการคัดลอก MyDatabase, MyTable และ IndexField ควรถูกแทนที่ด้วยชื่อของคุณ (แน่นอน)


1
นี่เป็นเรื่องยุ่งยากคุณจะแน่ใจได้อย่างไรว่าคุณกำลังคัดลอก id ที่ถูกต้องไปยังแถวที่ถูกต้องระหว่าง INSERT INTO ในบรรทัดที่ 3
Erno

id-column เป็นคอลัมน์ประจำตัว (ในตารางของฉัน) ดังนั้นฉันจึงไม่สนใจเรื่องค่านี้ ฉันแค่ต้องการระเบียนใหม่ที่มีค่าเดียวกับ "เก่า"
Jonas

9
สำหรับTempTableมันจะไม่ดีกว่าที่จะใช้#TempTableดังนั้นมันจึงเป็นตารางชั่วคราวจริงหรือ?
Jess

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 คุณสามารถคลิกขวาที่ตารางและ Script As Insert ได้อย่างง่ายดาย .. จากนั้นคุณสามารถยุ่งกับผลลัพธ์นั้นเพื่อสร้างแบบสอบถามของคุณ



6

ฉันมีปัญหาเดียวกันกับที่ฉันต้องการให้สคริปต์เดียวทำงานกับตารางที่มีการเพิ่มคอลัมน์เป็นระยะโดยนักพัฒนารายอื่น ไม่เพียงแค่นั้น แต่ฉันยังรองรับฐานข้อมูลเวอร์ชันต่างๆของเราเนื่องจากลูกค้าอาจไม่ได้อัปเดตเวอร์ชันปัจจุบันทั้งหมด

ฉันใช้วิธีแก้ปัญหาโดย 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

ฉันรู้ว่าคำตอบของฉันคืองานเลี้ยงสาย แต่วิธีที่ฉันแก้ไขนั้นแตกต่างจากคำตอบทั้งหมดเล็กน้อย

ฉันมีสถานการณ์ฉันต้องโคลนแถวในตารางยกเว้นไม่กี่คอลัมน์ คนส่วนน้อยจะมีค่านิยมใหม่ กระบวนการนี้ควรรองรับโดยอัตโนมัติสำหรับการเปลี่ยนแปลงตารางในอนาคต หมายความว่าโคลนเร็กคอร์ดโดยไม่ต้องระบุชื่อคอลัมน์ใด ๆ

แนวทางของฉันคือ

  1. Query Sys.Columns เพื่อรับรายการคอลัมน์ทั้งหมดสำหรับตารางและรวมชื่อของคอลัมน์ที่จะข้ามไปโดยที่ clause
  2. แปลงเป็น CSV เป็นชื่อคอลัมน์
  3. สร้างเลือก ... แทรกลงในสคริปต์ตามนี้


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


0

นี่คือวิธีที่ฉันใช้ 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")

ฉันไม่คิดว่าคุณต้องออกคำสั่ง SQL 5 คำสั่งแยกกันเพื่อทำสิ่งนี้ให้เสร็จสิ้น และคุณกำหนดใครในคำสั่งที่ 2 รหัสผลิตภัณฑ์นั้นควรเป็น 34567?
Jeyara

34567 เป็นเพียงตัวอย่าง คุณสามารถตั้งค่าเป็นตัวแปรหรืออะไรก็ได้ที่คุณต้องการ หากคุณมีวิธีที่ดีกว่าในการดำเนินการนี้ใน ASP Classic โปรดแจ้งให้เราทราบ :)
Daniel Nordh

คุณสามารถเขียน proc ที่จัดเก็บไว้เพื่อเรียกใช้สิ่งเหล่านี้ทั้งหมดในบรรทัดเดียว นอกจากนี้โดยปกติแล้ว PK เคยเป็นค่าที่เพิ่มขึ้นอัตโนมัติ ดังนั้นการมอบหมายให้ตัวเองไม่ใช่ความคิดที่ดี
Jeyara

คุณจะเขียนขั้นตอนดังกล่าวอย่างไร? ได้โปรดตรัสรู้ฉัน PK? หากคุณหมายถึงรหัสบทความในระบบของเราเราใช้รหัสบทความตามร้านค้าที่เราขายตัวอย่างเช่นร้านขายของเล่นของเราทั้งหมดมีหมายเลขบทความที่ขึ้นต้นด้วย 30 และร้านกีฬาของเราเริ่มต้นด้วย 60 นอกจากนี้เรายังประหยัดช่องว่างดังนั้นหากเรา ได้รับสีใหม่ตัวอย่างเช่นเราสามารถมีรหัสบทความถัดจากรายการอื่น ๆ ในประเภทเดียวกัน ตามที่กล่าวไว้นี่คือโซลูชันของฉันที่ใช้ได้ในระบบของเรา การตั้งค่าตัวแปรนั้นไม่สำคัญและโปรแกรมเมอร์ส่วนใหญ่จะเข้าใจว่าอะไรเหมาะกับพวกเขาและระบบของพวกเขา
Daniel Nordh

PK ย่อมาจากคีย์หลัก ในกรณีของคุณคือ "12345" โปรดดูstackoverflow.com/questions/21561657/…สำหรับวิธีการใช้ proc ที่เก็บไว้ใน Classic ASP หากคุณไม่รู้วิธีการ ในการดำเนินการนี้ให้ย้ายสิ่งเหล่านี้ทั้งหมดไปยัง proc ที่จัดเก็บไว้หนึ่งรายการและส่ง "12345" เป็นพารามิเตอร์ วิธีที่คุณใช้ในการทำงาน แต่แนะนำให้ใช้สคริปต์แบบกำหนดพารามิเตอร์ในปัจจุบัน
Jeyara
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.