SQL Server: เป็นไปได้หรือไม่ที่จะแทรกลงในสองตารางในเวลาเดียวกัน?


144

ฐานข้อมูลของฉันมีสามตารางเรียกว่าObject_Table, และData_Table Link_Tableตารางลิงก์ประกอบด้วยสองคอลัมน์ตัวตนของวัตถุและตัวตนของบันทึกข้อมูล

ฉันต้องการคัดลอกข้อมูลจากDATA_TABLEที่ซึ่งมันถูกเชื่อมโยงไปยังข้อมูลเฉพาะตัวของวัตถุที่ระบุและแทรกบันทึกที่เกี่ยวข้องลงในData_TableและLink_Tableเพื่อระบุตัวตนวัตถุที่แตกต่างกัน

ฉันสามารถทำได้โดยเลือกตัวแปรตารางและการวนซ้ำผ่านการแทรกสองครั้งสำหรับการวนซ้ำแต่ละครั้ง

นี่เป็นวิธีที่ดีที่สุดที่จะทำ?

แก้ไข : ฉันต้องการหลีกเลี่ยงการวนซ้ำด้วยเหตุผลสองประการข้อแรกคือฉันขี้เกียจและตาราง loop / temp ต้องการรหัสเพิ่มเติมรหัสเพิ่มเติมหมายถึงสถานที่ที่จะทำผิดและเหตุผลที่สองคือความกังวลเกี่ยวกับประสิทธิภาพ

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


ฉันไม่ได้รับความสนใจในการพยายามที่จะทำมันกับหนึ่งแทรกเมื่อทำมันด้วย 2 แทรกทำงานได้ดีอย่างสมบูรณ์ คุณหมายถึงว่าคุณต้องการให้แน่ใจว่าเม็ดมีดทั้งสองชิ้นนั้นสมบูรณ์หรือไม่ จากนั้นคุณจะต้องตรวจสอบคำสั่ง commit / rollback นี้
Philippe Grondier

2
ฉันจะมีความสุขกับสองแทรกมันเพียงว่าตัวตนที่ต้องถูกแทรกลงในตารางลิงค์เป็นตัวตนที่สร้างขึ้นในแทรกครั้งแรก
tpower

คำตอบ:


220

ในหนึ่งคำสั่ง : ไม่มี

ในการทำธุรกรรมเดียว: ใช่

BEGIN TRANSACTION
   DECLARE @DataID int;
   INSERT INTO DataTable (Column1 ...) VALUES (....);
   SELECT @DataID = scope_identity();
   INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT

ข่าวดีก็คือรหัสข้างต้นรับประกันได้ว่าเป็นอะตอมและสามารถส่งไปยังเซิร์ฟเวอร์จากแอปพลิเคชันไคลเอนต์ที่มีสตริงหนึ่ง sql ในการเรียกฟังก์ชั่นเดียวราวกับว่ามันเป็นหนึ่งคำสั่ง คุณสามารถใช้ทริกเกอร์กับตารางหนึ่งเพื่อรับผลกระทบของการแทรกเดี่ยว อย่างไรก็ตามในที่สุดก็ยังมีสองข้อความและคุณอาจไม่ต้องการเรียกใช้ทริกเกอร์สำหรับการแทรกทุกครั้ง


2
นี่คือสิ่งที่ฉันกำลังค้นหาเป็นเวลานาน ขอบคุณ :)
nandu.com

33
@ Joel คำถามที่ดี สมมุติว่ามีคนต้องการความเป็นจริงทางเลือกและคุณเป็นผู้ถือข่าวร้าย ;)
Kirk Woll

2
สิ่งนี้บันทึกวันของฉันในวันนี้ :) thanx
Shekhar_Pro

12
นี่ไม่ได้แก้ปัญหา เขาต้องการแทรกข้อมูลที่อ่านจาก Object_Table คือinsert into ... select ...คำสั่ง โค้ดด้านบนอ่านหรือวนลูปผ่านข้อมูล Object_Table อย่างไร จากนั้นคุณยังต้องใช้ตัวแปรตารางที่ผู้ถามไม่ต้องการทำ
hofnarwillie

8
แน่นอนว่านี่จะช่วยแก้ปัญหา บางทีฉันอาจจะไม่ได้เขียนทั้งหมดของรหัสนี้ แต่แล้ว OP ไม่ได้แบ่งปันคอลัมน์ทั้งหมดที่เขาต้องการที่จะคัดลอกทั้ง คุณสมบัติที่แสดงในคำตอบนี้จะช่วยให้ OP ทำสิ่งที่เขาขอ ... เรียกใช้แบบสอบถามเพื่อสร้างระเบียนรับ ID ของระเบียนใหม่และใช้ ID นั้นสำหรับระเบียนที่สองในวิธีอะตอมมิก OP ทราบวิธีการใส่ / เลือกเรียบร้อยแล้ว นี่คือชิ้นส่วนที่เขาหายไป
Joel Coehoorn

35

คุณยังคงต้องมีสองINSERTข้อความ แต่ดูเหมือนว่าคุณต้องการที่จะได้รับIDENTITYจากการแทรกครั้งแรกและใช้มันในครั้งที่สองซึ่งในกรณีนี้คุณอาจต้องการค้นหาOUTPUTหรือOUTPUT INTO: http://msdn.microsoft.com/en- เรา / ห้องสมุด / ms177564.aspx


1
ขอบคุณ! ฉันไม่รู้เกี่ยวกับคำสำคัญ OUTPUT ซึ่งเป็นสิ่งที่ฉันต้องการ +1
Rex Morgan

เป็นไปได้หรือไม่ที่จะใช้ "OUTPUT INTO" สองครั้งในหนึ่ง sql
V.Wu

@V.Wu ฉันไม่คิดอย่างนั้นฉันจะต้องตั้งค่าการทดสอบเพื่อดู
เคด Roux

18

ต่อไปนี้เป็นการตั้งค่าสถานการณ์ที่ฉันมีโดยใช้ตัวแปรตาราง

DECLARE @Object_Table TABLE
(
    Id INT NOT NULL PRIMARY KEY
)

DECLARE @Link_Table TABLE
(
    ObjectId INT NOT NULL,
    DataId INT NOT NULL
)

DECLARE @Data_Table TABLE
(
    Id INT NOT NULL Identity(1,1),
    Data VARCHAR(50) NOT NULL
)

-- create two objects '1' and '2'
INSERT INTO @Object_Table (Id) VALUES (1)
INSERT INTO @Object_Table (Id) VALUES (2)

-- create some data
INSERT INTO @Data_Table (Data) VALUES ('Data One')
INSERT INTO @Data_Table (Data) VALUES ('Data Two')

-- link all data to first object
INSERT INTO @Link_Table (ObjectId, DataId)
SELECT Objects.Id, Data.Id
FROM @Object_Table AS Objects, @Data_Table AS Data
WHERE Objects.Id = 1

ขอบคุณคำตอบอื่นที่ชี้ให้ฉันไปที่ส่วนคำสั่ง OUTPUT ฉันสามารถแสดงวิธีแก้ปัญหา:

-- now I want to copy the data from from object 1 to object 2 without looping
INSERT INTO @Data_Table (Data)
OUTPUT 2, INSERTED.Id INTO @Link_Table (ObjectId, DataId)
SELECT Data.Data
FROM @Data_Table AS Data INNER JOIN @Link_Table AS Link ON Data.Id = Link.DataId
                INNER JOIN @Object_Table AS Objects ON Link.ObjectId = Objects.Id 
WHERE Objects.Id = 1

ปรากฎว่ามันไม่ใช่เรื่องง่ายในชีวิตจริงเนื่องจากข้อผิดพลาดดังต่อไปนี้

OUTPUT INTO clause ไม่สามารถอยู่บนทั้งสองด้านของความสัมพันธ์ (คีย์หลัก, foreign key)

ฉันยังคงOUTPUT INTOเป็นตารางชั่วคราวและจบด้วยการแทรกปกติ ดังนั้นฉันสามารถหลีกเลี่ยงการวนรอบของฉัน แต่ฉันไม่สามารถหลีกเลี่ยงตารางชั่วคราว



6

ดูเหมือนว่าตารางลิงก์จะรวบรวมข้อมูลมากมาย: ความสัมพันธ์จำนวนมากระหว่างตารางวัตถุและตารางข้อมูล

ข้อเสนอแนะของฉันคือการใช้ขั้นตอนการจัดเก็บเพื่อจัดการธุรกรรม เมื่อคุณต้องการแทรกไปยังวัตถุหรือตารางข้อมูลทำการแทรกของคุณรับ ID ใหม่และแทรกลงในตารางการเชื่อมโยง

สิ่งนี้ช่วยให้ตรรกะทั้งหมดของคุณยังคงอยู่ในแค็ปซูลง่ายที่จะเรียก


ทำไมไม่มีใครโหวตคุณอีกล่ะ ขั้นตอนการจัดเก็บเป็นวิธีที่ชัดเจนและดีที่สุด รวมคำตอบของคุณเข้ากับคำตอบของ Joel Coehoorn และคุณจะได้คำตอบที่ดีที่สุด!
Rhyous

4

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


2
การกระทำเป็นแบบปรมาณูหากพวกเขากำลังทำธุรกรรมไม่ปรมาณู "มากหรือน้อย" ปรมาณู สิ่งที่ไม่จำเป็นต้องรับประกันคือระดับของการแยกเว้นแต่ว่าคุณจะระบุไว้
Dave Markle

4

คุณอาจสร้างมุมมองการเลือกชื่อคอลัมน์ที่ต้องการโดยคำสั่งแทรกของคุณเพิ่มทริกเกอร์ INSTEAD OF INSERT และแทรกลงในมุมมองนี้


4

ฉันต้องการเครียดกับการใช้งาน

SET XACT_ABORT ON;

สำหรับธุรกรรม MSSQL ที่มีหลายคำสั่ง sql

ดู: https://msdn.microsoft.com/en-us/library/ms188792.aspx พวกเขาเป็นตัวอย่างที่ดีมาก

ดังนั้นรหัสสุดท้ายควรมีลักษณะดังนี้:

SET XACT_ABORT ON;

BEGIN TRANSACTION
   DECLARE @DataID int;
   INSERT INTO DataTable (Column1 ...) VALUES (....);
   SELECT @DataID = scope_identity();
   INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT

2

ส่วนแทรกสามารถทำงานได้ครั้งละหนึ่งตารางเท่านั้น แทรกหลายรายการจะต้องมีหลายงบ

ฉันไม่รู้ว่าคุณต้องทำการวนลูปผ่านตัวแปรตาราง - คุณไม่สามารถใช้การเพิ่มมวลเข้าไปในตารางเดียวหรือไม่แล้วมวลแทรกเข้าไปอีกอัน?

โดยวิธี - ฉันเดาคุณหมายถึงการคัดลอกข้อมูลจาก Object_Table; มิฉะนั้นคำถามก็ไม่สมเหตุสมผล


2

ก่อนที่จะสามารถทำการแทรกแบบหลายค่าใน Oracle คุณสามารถใช้เคล็ดลับที่เกี่ยวข้องกับการแทรกลงในมุมมองที่มีทริกเกอร์ INSTEAD OF ที่กำหนดไว้เพื่อทำการแทรก สามารถทำได้ใน SQL Server หรือไม่


-1
-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters 
-- command (Ctrl-Shift-M) to fill in the parameter 
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE InsetIntoTwoTable

(
@name nvarchar(50),
@Email nvarchar(50)
)

AS
BEGIN

    SET NOCOUNT ON;


    insert into dbo.info(name) values (@name)
    insert into dbo.login(Email) values (@Email)
END
GO

คุณสามารถเพิ่มคำอธิบายได้ไหม?
Kyll

-2

// ถ้าคุณต้องการแทรกเหมือนกับตารางแรก

$qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";

$result = @mysql_query($qry);

$qry2 = "INSERT INTO table2 (one,two, three) VVALUES('$one','$two','$three')";

$result = @mysql_query($qry2);

// หรือถ้าคุณต้องการแทรกบางส่วนของตารางหนึ่ง

 $qry = "INSERT INTO table (one, two, three) VALUES('$one','$two','$three')";


  $result = @mysql_query($qry);

 $qry2 = "INSERT INTO table2 (two) VALUES('$two')";

 $result = @mysql_query($qry2);

// ฉันรู้ว่ามันดูดีเกินกว่าที่จะถูกต้อง แต่ใช้งานได้และคุณสามารถเพิ่มการสืบค้นของเพียงแค่เปลี่ยน

    "$qry"-number and number in @mysql_query($qry"")

ฉันมี 17 ตารางที่ใช้งานได้


หากมีบางอย่างผิดปกติในส่วนแทรก? ส่วนแทรกของคุณจะไม่สมบูรณ์ ขวา? ถ้าทำเช่นนั้น .. คุณมีฟังก์ชั่นย้อนกลับเพื่อทำการรักษาหรือไม่? ถ้าไม่ใช่ .. คุณมีปัญหากับความถูกต้องของข้อมูล
deepcell

7
-1 คำตอบนี้ดูเหมือนจะใช้วิธี MySQL ใน PHP คำถามนี้ถูกแท็กsqlและsql-serverโดยไม่มีการกล่าวถึง MySQL หรือ PHP
mskfisher
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.