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?

Author: tpower, 2008-10-06

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

 186
Author: Joel Coehoorn,
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

 29
Author: Cade Roux,
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.

 16
Author: tpower,
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.

 5
Author: Bob Probst,
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.

 4
Author: Craig,
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.

 4
Author: devio,
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.

 2
Author: Carlton Jenke,
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?

 2
Author: David Aldridge,
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
 2
Author: Sergei Zinovyev,
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
 -1
Author: FakirPori,
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.

 -2
Author: Brion,
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