SQL Server: Apakah mungkin untuk memasukkan ke dalam dua tabel sekaligus?

143

Database saya berisi tiga tabel yang disebut Object_Table, Data_Tabledan Link_Table. Tabel tautan hanya berisi dua kolom, identitas catatan objek dan identitas catatan data.

Saya ingin menyalin data dari DATA_TABLEmana itu terkait dengan satu identitas objek yang diberikan dan menyisipkan catatan yang sesuai ke Data_Tabledan Link_Tableuntuk identitas objek tertentu yang diberikan.

Saya bisa melakukan ini dengan memilih ke dalam variabel tabel dan perulangan melalui melakukan dua menyisipkan untuk setiap iterasi.

Apakah ini cara terbaik untuk melakukannya?

Sunting : Saya ingin menghindari loop karena dua alasan, yang pertama adalah saya malas dan loop / temp table membutuhkan lebih banyak kode, lebih banyak kode berarti lebih banyak tempat untuk membuat kesalahan dan alasan kedua adalah kekhawatiran tentang kinerja.

Saya bisa menyalin semua data dalam satu sisipan tetapi bagaimana cara mendapatkan tabel tautan untuk menautkan ke catatan data baru di mana setiap catatan memiliki id baru?

tpower
sumber
Saya tidak tertarik mencoba melakukannya dengan SATU sisipan, ketika melakukannya dengan 2 sisipan bekerja dengan baik. Maksud Anda, Anda ingin memastikan kedua sisipan tersebut selesai? Maka Anda harus memeriksa instruksi commit / rollback ini.
Philippe Grondier
2
Saya akan senang dengan dua sisipan, hanya saja identitas yang perlu dimasukkan ke dalam tabel tautan adalah identitas yang dihasilkan pada sisipan pertama.
tpower

Jawaban:

219

Dalam satu pernyataan : Tidak.

Dalam satu transaksi : Ya

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

Kabar baiknya adalah bahwa kode di atas juga dijamin atom , dan dapat dikirim ke server dari aplikasi klien dengan satu string sql dalam panggilan fungsi tunggal seolah-olah itu adalah satu pernyataan. Anda juga bisa menerapkan pemicu ke satu tabel untuk mendapatkan efek dari satu sisipan. Namun, pada akhirnya ini masih dua pernyataan dan Anda mungkin tidak ingin menjalankan pelatuk untuk setiap sisipan.

Joel Coehoorn
sumber
2
Ini yang saya cari sejak lama. Terima kasih :)
nandu.com
33
@ Joel, pertanyaan bagus. Mungkin seseorang menginginkan realitas alternatif dan Anda adalah pembawa berita buruk. ;)
Kirk Woll
2
ini menyelamatkan hari saya hari ini :) thanx
Shekhar_Pro
12
Ini tidak menyelesaikan masalah. Dia ingin memasukkan data yang dibaca dari Object_Table. Yaitu sebuah insert into ... select ...pernyataan. Bagaimana kode di atas membaca atau mengulangi data Object_Table. Anda masih perlu menggunakan variabel tabel yang tidak ingin dilakukan oleh penanya.
hofnarwillie
8
Tentu ini menyelesaikan masalah. Mungkin saya tidak menulis semua kode untuk ini, tetapi OP juga tidak membagikan semua kolom yang ingin dia salin. Fitur yang ditunjukkan dalam jawaban ini akan memungkinkan OP untuk melakukan apa yang dia minta ... menjalankan kueri untuk membuat catatan, mendapatkan ID dari catatan baru, dan menggunakan ID itu untuk catatan kedua dengan cara atom. OP sudah tahu cara melakukan insert / select. Ini adalah bagian yang dia lewatkan.
Joel Coehoorn
35

Anda masih membutuhkan dua INSERTpernyataan, tetapi sepertinya Anda ingin mendapatkan IDENTITYdari sisipan pertama dan menggunakannya di yang kedua, dalam hal ini, Anda mungkin ingin melihat ke dalam OUTPUTatau OUTPUT INTO: http://msdn.microsoft.com/en- us / library / ms177564.aspx

Cade Roux
sumber
1
Terima kasih! Saya tidak tahu tentang kata kunci OUTPUT, persis apa yang saya cari. +1
Rex Morgan
apakah mungkin menggunakan "OUTPUT INTO" dua kali dalam satu sql
V.Wu
@ V.Apa saya tidak berpikir begitu, saya harus mengatur tes untuk melihat.
Cade Roux
18

Berikut ini mengatur situasi yang saya miliki, menggunakan variabel tabel.

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

Berkat jawaban lain yang mengarahkan saya ke klausa OUTPUT saya bisa menunjukkan solusinya:

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

Namun ternyata itu tidak sesederhana itu dalam kehidupan nyata karena kesalahan berikut

klausa OUTPUT INTO tidak dapat berada di kedua sisi hubungan (kunci utama, kunci asing)

Saya masih bisa OUTPUT INTOtabel temp dan kemudian selesai dengan memasukkan normal. Jadi saya bisa menghindari loop saya tetapi saya tidak bisa menghindari tabel temp.

tpower
sumber
6

Kedengarannya seperti tabel Tautan menangkap banyak: banyak hubungan antara tabel Objek dan tabel Data.

Saran saya adalah menggunakan prosedur tersimpan untuk mengelola transaksi. Saat Anda ingin menyisipkan ke objek atau tabel Data melakukan sisipan Anda, dapatkan ID baru dan masukkan ke tabel Link.

Ini memungkinkan semua logika Anda untuk tetap dienkapsulasi dalam satu sproc yang mudah dipanggil.

Bob Probst
sumber
Mengapa orang lain tidak mengangkat Anda? Prosedur tersimpan adalah cara yang jelas dan terbaik. Gabungkan jawaban Anda dengan jawaban Joel Coehoorn dan Anda mendapatkan jawaban terbaik!
Rhyous
4

Jika Anda ingin tindakan lebih atau kurang atom, saya akan pastikan untuk membungkusnya dalam suatu transaksi. Dengan begitu Anda dapat memastikan keduanya terjadi atau keduanya tidak terjadi sesuai kebutuhan.

Craig
sumber
2
Tindakannya adalah atom jika mereka dibungkus dalam suatu transaksi, bukan atom "kurang lebih". Apa yang tidak perlu dijamin adalah tingkat isolasi, kecuali Anda menentukannya.
Dave Markle
4

Anda dapat membuat Tampilan dengan memilih nama kolom yang diperlukan oleh pernyataan penyisipan Anda, menambahkan BUKAN PEMASANG INSERT, dan masukkan ke dalam tampilan ini.

devio
sumber
4

Saya ingin menekankan pada penggunaan

SET XACT_ABORT ON;

untuk transaksi MSSQL dengan beberapa pernyataan sql.

Lihat: https://msdn.microsoft.com/en-us/library/ms188792.aspx Mereka memberikan contoh yang sangat baik.

Jadi, kode final akan terlihat seperti berikut:

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
Sergei Zinovyev
sumber
2

Sisipan hanya dapat beroperasi pada satu tabel pada satu waktu. Banyak Sisipan harus memiliki banyak pernyataan.

Saya tidak tahu bahwa Anda perlu melakukan perulangan melalui variabel tabel - tidak bisakah Anda menggunakan sisipan massa ke dalam satu tabel, lalu masukkan massa ke yang lainnya?

By the way - Saya kira maksud Anda menyalin data dari Object_Table; kalau tidak, pertanyaannya tidak masuk akal.

Carlton Jenke
sumber
2

Sebelum dapat melakukan penyisipan multitable di Oracle, Anda bisa menggunakan trik yang melibatkan penyisipan ke tampilan yang memiliki BUKAN pemicu BUKAN didefinisikan untuk melakukan sisipan. Bisakah ini dilakukan dalam SQL Server?

David Aldridge
sumber
-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
FakirPori
sumber
Bisakah Anda menambahkan beberapa penjelasan?
Kyll
-2

// jika Anda ingin memasukkan yang sama dengan tabel pertama

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

// atau jika Anda ingin memasukkan bagian tabel tertentu

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

// aku tahu itu kelihatannya terlalu bagus untuk menjadi benar, tapi itu berhasil dan kamu dapat terus menambahkan kueri hanya mengubah

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

Saya memiliki 17 tabel yang berfungsi.

Brion
sumber
jika ada yang salah di tengah sisipan? Sisipan Anda tidak akan lengkap. Baik? Jika demikian .. apakah Anda memiliki fungsi rollback untuk mengobatinya? Jika tidak .. Anda memiliki masalah dengan integritas data Anda.
deepcell
7
-1. Jawaban ini tampaknya menggunakan metode MySQL di PHP. Pertanyaan ini ditandai dengan sql dan sql-server , tanpa menyebutkan MySQL atau PHP.
mskfisher