2008-10-06 77 views
105

Cơ sở dữ liệu của tôi chứa ba bảng gọi là Object_Table, Data_TableLink_Table. Bảng liên kết chỉ chứa hai cột, danh tính của một bản ghi đối tượng và bản sắc của một bản ghi dữ liệu.Máy chủ SQL: Có thể chèn vào hai bảng cùng một lúc không?

Tôi muốn sao chép dữ liệu từ DATA_TABLE nơi nó được liên kết với một danh tính đối tượng nhất định và chèn các bản ghi tương ứng vào Data_TableLink_Table để nhận dạng đối tượng đã cho khác.

I có thể thực hiện việc này bằng cách chọn biến bảng và vòng lặp thông qua thực hiện hai lần chèn cho mỗi lần lặp.

Đây có phải là cách tốt nhất để làm điều đó không?

Chỉnh sửa: Tôi muốn tránh vòng lặp vì hai lý do, thứ nhất là bảng lười/bảng tạm thời yêu cầu mã nhiều hơn. một mối quan tâm về hiệu suất.

Tôi có thể sao chép tất cả dữ liệu trong một lần chèn nhưng làm cách nào để bảng liên kết liên kết đến bản ghi dữ liệu mới trong đó mỗi bản ghi có id mới?

+0

Tôi không nhận được sự quan tâm của cố gắng để làm điều đó với ONE chèn, khi thực hiện nó với 2 chen hoạt động hoàn hảo tốt. Bạn có nghĩa là bạn muốn đảm bảo rằng cả 2 lần chèn đều được hoàn thành? Sau đó, bạn sẽ phải kiểm tra hướng dẫn commit/rollback này. –

+1

Tôi sẽ hài lòng với hai lần chèn, chỉ là các danh tính cần được chèn vào bảng liên kết là các danh tính được tạo trong lần chèn đầu tiên. – tpower

Trả lời

15

Sau đây thiết lập tình huống tôi có, sử dụng các biến bảng.

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 

Nhờ khác answer mà chỉ cho tôi hướng tới mệnh đề OUTPUT Tôi có thể chứng minh một giải pháp:

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

Hóa ra tuy nhiên nó không phải là đơn giản trong cuộc sống thực vì các lỗi sau

mệnh đề OUTPUT INTO không được ở hai bên của mối quan hệ (khóa chính, quan hệ nước ngoài )

Tôi vẫn có thể OUTPUT INTO bảng tạm thời và sau đó kết thúc bằng chèn thông thường. Vì vậy, tôi có thể tránh vòng lặp của tôi nhưng tôi không thể tránh được bảng tạm thời.

+0

[Nếu bạn đang sử dụng SQL Server 2008, hãy xem câu trả lời của tôi ở đây để biết cách khắc phục lỗi này] (http://stackoverflow.com/questions/7408204/is-there-a-way-to-do-another-query- trong-the-insert-query/7415501 # 7415501) –

4

Nếu bạn muốn các hành động ít nhiều nguyên tử, tôi chắc chắn sẽ bao bọc chúng trong một giao dịch. Bằng cách đó bạn có thể chắc chắn cả hai đã xảy ra hoặc cả hai đều không xảy ra khi cần thiết.

+2

Các hành động là nguyên tử nếu chúng được bao bọc trong một giao dịch chứ không phải nguyên tử "nhiều hay ít". Điều không nhất thiết được đảm bảo là mức độ cô lập, trừ khi bạn chỉ định như vậy. –

2

Chèn chỉ có thể hoạt động trên một bảng tại một thời điểm. Nhiều Phụ trang phải có nhiều câu lệnh.

Tôi không biết rằng bạn cần thực hiện vòng lặp thông qua biến bảng - bạn không thể sử dụng chèn khối lượng vào một bảng, sau đó chèn khối lượng vào bảng khác?

Nhân tiện - tôi đoán bạn có nghĩa là sao chép dữ liệu từ Object_Table; nếu không câu hỏi không có ý nghĩa.

27

Bạn vẫn cần hai INSERT báo cáo, nhưng có vẻ như bạn muốn để có được những IDENTITY từ chèn đầu tiên và sử dụng nó trong lần thứ hai, trong trường hợp này, bạn có thể muốn xem xét OUTPUT hoặc OUTPUT INTO: http://msdn.microsoft.com/en-us/library/ms177564.aspx

+1

Cảm ơn! Tôi không biết về từ khóa OUTPUT, chính xác những gì tôi đang tìm kiếm. +1 –

170

Trong một tuyên bố : số

Trong một giao dịch: Có

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

Tin tốt là mã trên cũng được đảm bảo là nguyên tử và có thể được gửi tới máy chủ từ ứng dụng khách với một chuỗi sql trong một cuộc gọi hàm như thể đó là một câu lệnh. Bạn cũng có thể áp dụng một kích hoạt cho một bảng để có được hiệu ứng của một chèn đơn. Tuy nhiên, cuối cùng vẫn là hai câu lệnh và có thể bạn không muốn chạy trình kích hoạt cho mỗi lần chèn.

+0

Cảm ơn bạn đã trích đoạn mã này. –

+1

Đây là những gì tôi đang tìm kiếm trong một thời gian dài. Cảm ơn :) –

+9

Tại sao điều này chỉ được đánh giá thấp? –

4

Có vẻ như bảng Liên kết nắm bắt được nhiều mối quan hệ giữa bảng Đối tượng và Bảng dữ liệu.

Đề xuất của tôi là sử dụng quy trình được lưu trữ để quản lý giao dịch. Khi bạn muốn chèn vào bảng Object hoặc Data thực hiện chèn của bạn, lấy các ID mới và chèn chúng vào bảng Link.

Điều này cho phép tất cả logic của bạn được duy trì trong một cuộc gọi dễ dàng.

+0

Tại sao không có ai khác tán thành bạn? Các thủ tục được lưu trữ là cách rõ ràng và tốt nhất. Kết hợp câu trả lời của bạn với câu trả lời của Joel Coehoorn và bạn nhận được câu trả lời tốt nhất! – Rhyous

4

Bạn có thể tạo Chế độ xem chọn tên cột được yêu cầu bởi câu lệnh chèn của bạn, thêm một INSTEAD OF INSERT Trigger và chèn vào chế độ xem này.

2

Trước khi có thể thực hiện chèn nhiều lần trong Oracle, bạn có thể sử dụng một mẹo liên quan đến chèn vào khung nhìn có trình kích hoạt INSTEAD OF được xác định trên nó để thực hiện chèn. Điều này có thể được thực hiện trong SQL Server?

-2

// nếu bạn muốn chèn giống như bảng đầu tiên

$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); 

// hoặc nếu bạn muốn chèn một số phần của bảng một

$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); 

// i biết có vẻ quá tốt để đúng, nhưng nó hoạt động và bạn có thể tiếp tục thêm truy vấn chỉ cần thay đổi

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

Tôi có 17 bảng này đã làm việc trong.

+0

nếu có gì đó sai ở giữa chèn? Chèn của bạn sẽ không đầy đủ. đúng? Nếu làm như vậy .. bạn có một chức năng rollback để xử lý nó? Nếu không .. bạn có một vấn đề với tính toàn vẹn dữ liệu của bạn. – B4NZ41

+6

-1. Câu trả lời này dường như đang sử dụng các phương thức MySQL trong PHP. Câu hỏi được gắn thẻ [tag: sql] và [tag: sql-server], không đề cập đến MySQL hoặc PHP. – mskfisher

-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 
+0

Bạn có thể thêm một số giải thích? –

+1

bạn đã đọc câu hỏi chưa? –

2

Tôi muốn nhấn mạnh về việc sử dụng

SET XACT_ABORT ON; 

cho giao dịch MSSQL với nhiều câu lệnh sql.

Xem: https://msdn.microsoft.com/en-us/library/ms188792.aspx Chúng cung cấp một ví dụ rất tốt.

Vì vậy, mã cuối cùng sẽ trông giống như sau:

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 
Các vấn đề liên quan