SQL Server: czy można wstawić do dwóch tabel jednocześnie?
Moja baza danych zawiera trzy tabele o nazwie Object_Table
, Data_Table
i Link_Table
. Tabela łącza zawiera tylko dwie kolumny, tożsamość rekordu obiektu i tożsamość rekordu danych.
Chcę skopiować dane z DATA_TABLE
, Gdzie są powiązane z jedną podaną tożsamością obiektu i wstawić odpowiednie rekordy do Data_Table
i Link_Table
dla innej podanej tożsamości obiektu.
I można zrobić to, wybierając do zmiennej tabeli i zapętlając poprzez wykonanie dwóch wstawek dla każdej iteracja.
Czy to najlepszy sposób?Edit: chcę uniknąć pętli z dwóch powodów, Pierwszy jest to, że jestem leniwy i tabela loop / temp wymaga więcej kodu, więcej kodu oznacza więcej miejsc do popełnienia błędu, a drugi powód to troska o wydajność.
Mogę skopiować wszystkie dane w jednej wstawce, ale jak uzyskać tabelę linków, aby połączyć się z nowymi rekordami danych, gdzie każdy rekord ma nowy identyfikator?
11 answers
W Jednym oświadczeniu : nie.
W jednej transakcji : Tak
BEGIN TRANSACTION
DECLARE @DataID int;
INSERT INTO DataTable (Column1 ...) VALUES (....);
SELECT @DataID = scope_identity();
INSERT INTO LinkTable VALUES (@ObjectID, @DataID);
COMMIT
Dobrą wiadomością jest to, że powyższy kod jest również gwarantowany jako atomic i może być wysłany do serwera z aplikacji klienckiej z jednym ciągiem sql w jednym wywołaniu funkcji, tak jakby było to jedno polecenie. Można również zastosować wyzwalacz do jednej tabeli, aby uzyskać efekt pojedynczej wkładki. Jednak ostatecznie to nadal dwa stwierdzenia i prawdopodobnie nie chcesz uruchomić wyzwalacza dla co wstawić.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-06 16:13:02
Nadal potrzebujesz dwóch INSERT
instrukcji, ale wygląda na to, że chcesz pobrać IDENTITY
z pierwszej wkładki i użyć jej w drugiej, w takim przypadku możesz zajrzeć do OUTPUT
lub OUTPUT INTO
: http://msdn.microsoft.com/en-us/library/ms177564.aspx
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 16:49:21
Poniżej przedstawiono sytuację, którą miałem, używając zmiennych tabelkowych.
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
Dzięki innej odpowiedzi która wskazała mi punkt wyjścia mogę zademonstrować rozwiązanie:
-- 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
Okazuje się jednak, że nie jest to takie proste w prawdziwym życiu z powodu następującego błędu
Klauzula OUTPUT INTO nie może być włączona po obu stronach a (klucz podstawowy, zagraniczny key) relationship
I can still OUTPUT INTO
A temp table and then finish with zwykła wkładka. Więc mogę uniknąć mojej pętli, ale nie mogę uniknąć tabeli tymczasowej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:45
Wygląda na to, że tabela łącza przechwytuje relację many: many pomiędzy tabelą obiektu a tabelą danych.
Moja sugestia to użycie procedury składowanej do zarządzania transakcjami. Jeśli chcesz wstawić do tabeli obiektów lub danych wykonaj wstawianie, Pobierz Nowe identyfikatory i wstaw je do tabeli łącza.
Dzięki temu cała twoja logika pozostanie zamknięta w jednym łatwym do wywołania sproc.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 16:50:33
Jeśli chcesz, aby akcje były mniej lub bardziej atomowe, zadbam o to, aby zawinąć je w transakcję. W ten sposób możesz mieć pewność, że oba wydarzenia miały miejsce lub oba nie miały miejsca w razie potrzeby.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 16:42:25
Możesz utworzyć widok wybierając nazwy kolumn wymagane przez instrukcję insert, dodać WYZWALACZ zamiast INSERT i wstawić do tego widoku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 16:53:26
Insert może działać tylko na jednym stole na raz. Wiele wstawek musi mieć wiele poleceń.
Nie wiem, czy trzeba zrobić pętlę przez zmienną tabeli - nie można po prostu użyć insert mass do jednej tabeli, a następnie insert mass do drugiej?
Przy okazji-zgaduję, że masz na myśli skopiowanie danych z Object_Table; w przeciwnym razie pytanie nie ma sensu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 16:42:51
Przed wykonaniem wielozadaniowego wstawiania w Oracle możesz użyć sztuczki polegającej na wstawieniu do widoku, który miał zdefiniowany WYZWALACZ zamiast wyzwalacza, aby wykonać wstawianie. Czy można to zrobić w SQL Server?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 17:25:59
Chcę podkreślić, że używam
SET XACT_ABORT ON;
Dla transakcji MSSQL z wieloma poleceniami sql.
Zobacz: https://msdn.microsoft.com/en-us/library/ms188792.aspx Stanowią one bardzo dobry przykład.
Zatem końcowy kod powinien wyglądać następująco:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-01 01:43:16
-- ================================================
-- 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-07 13:35:09
/ / Jeśli chcesz wstawić to samo co pierwsza tabela
$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);
/ / lub jeśli chcesz wstawić pewne części tabeli pierwszej
$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);
/ / wiem, że wygląda zbyt dobrze, aby mieć rację, ale to działa i możesz dodawać zapytanie tylko zmienić
"$qry"-number and number in @mysql_query($qry"")
Mam 17 tabel to działa w.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-09 06:45:47