SQL Server: Ist es möglich, gleichzeitig in zwei Tabellen einzufügen?

143

Meine Datenbank enthält drei Tabellen genannt Object_Table, Data_Tableund Link_Table. Die Verknüpfungstabelle enthält nur zwei Spalten, die Identität eines Objektdatensatzes und eine Identität eines Datensatzes.

Ich möchte die Daten kopieren, von DATA_TABLEdenen sie mit einer bestimmten Objektidentität verknüpft sind, und entsprechende Datensätze in Data_Tableund Link_Tablefür eine andere bestimmte Objektidentität einfügen .

Ich kann dies tun, indem ich in eine Tabellenvariable wähle und die Schleife durch zwei Einfügungen für jede Iteration mache.

Ist das der beste Weg, es zu tun?

Bearbeiten : Ich möchte eine Schleife aus zwei Gründen vermeiden: Der erste Grund ist, dass ich faul bin und eine Schleifen- / temporäre Tabelle mehr Code erfordert. Mehr Code bedeutet mehr Stellen, an denen Fehler gemacht werden können, und der zweite Grund ist ein Problem mit der Leistung.

Ich kann alle Daten in einer Einfügung kopieren, aber wie kann die Verknüpfungstabelle mit den neuen Datensätzen verknüpft werden, in denen jeder Datensatz eine neue ID hat?

tpower
quelle
Ich habe nicht das Interesse, es mit EINEM Einsatz zu versuchen, wenn es mit 2 Einsätzen perfekt funktioniert. Meinen Sie damit, dass Sie sicherstellen möchten, dass die beiden Beilagen vollständig sind? Dann müssen Sie diese Commit / Rollback-Anweisung überprüfen.
Philippe Grondier
2
Ich würde mich über zwei Einfügungen freuen. Es ist nur so, dass die Identitäten, die in die Verknüpfungstabelle eingefügt werden müssen, die Identitäten sind, die in der ersten Einfügung generiert wurden.
tpower

Antworten:

220

In einer Aussage : Nein.

In einer Transaktion : Ja

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

Die gute Nachricht ist, dass der obige Code garantiert auch so ist atomar ist und von einer Clientanwendung mit einer SQL-Zeichenfolge in einem einzelnen Funktionsaufruf an den Server gesendet werden kann, als wäre es eine Anweisung. Sie können auch einen Trigger auf eine Tabelle anwenden, um den Effekt einer einzelnen Einfügung zu erzielen. Letztendlich sind es jedoch immer noch zwei Anweisungen, und Sie möchten wahrscheinlich nicht den Auslöser für jede Einfügung ausführen .

Joel Coehoorn
quelle
2
Das ist es, wonach ich lange suche. Danke :)
nandu.com
33
@ Joel, tolle Frage. Vermutlich wünschte sich jemand eine alternative Realität und Sie waren der Überbringer schlechter Nachrichten. ;)
Kirk Woll
2
das hat mir heute den Tag gerettet :) Danke
Shekhar_Pro
12
Dies löst das Problem nicht. Er möchte aus Object_Table gelesene Daten einfügen. Dh eine insert into ... select ...Aussage. Wie liest oder durchläuft der obige Code die Object_Table-Daten? Sie müssen dann noch eine Tabellenvariable verwenden, die der Fragesteller nicht tun wollte.
Hofnarwillie
8
Sicher löst dies das Problem. Vielleicht habe ich nicht den gesamten Code dafür geschrieben, aber dann hat das OP auch nicht alle Spalten geteilt, die er kopieren wollte. Mit den in dieser Antwort gezeigten Funktionen kann das OP das tun, was es verlangt ... eine Abfrage ausführen, um einen Datensatz zu erstellen, die ID des neuen Datensatzes abzurufen und diese ID auf atomare Weise für einen zweiten Datensatz zu verwenden. Das OP weiß bereits, wie man einfügt / auswählt. Dies ist das Stück, das ihm fehlte.
Joel Coehoorn
35

Sie benötigen noch zwei INSERTAnweisungen, aber es hört sich so an, als ob Sie die Anweisungen IDENTITYaus der ersten Einfügung abrufen und in der zweiten verwenden möchten. In diesem Fall möchten Sie möglicherweise Folgendes prüfen OUTPUToder OUTPUT INTO: http://msdn.microsoft.com/en- us / library / ms177564.aspx

Cade Roux
quelle
1
Vielen Dank! Ich wusste nicht genau, wonach ich suchte, nach dem Schlüsselwort OUTPUT. +1
Rex Morgan
Ist es möglich, "OUTPUT INTO" zweimal in einem SQL zu verwenden
V.Wu
@ V.Wu Ich glaube nicht, ich muss einen Test einrichten, um zu sehen.
Cade Roux
18

Im Folgenden wird die Situation anhand von Tabellenvariablen beschrieben.

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

Dank einer weiteren Antwort , die mich auf die OUTPUT-Klausel hinwies, kann ich eine Lösung demonstrieren:

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

Es stellt sich jedoch heraus, dass es im wirklichen Leben aufgrund des folgenden Fehlers nicht so einfach ist

Die OUTPUT INTO-Klausel darf sich nicht auf beiden Seiten einer Beziehung (Primärschlüssel, Fremdschlüssel) befinden

Ich kann noch OUTPUT INTOeine temporäre Tabelle erstellen und dann mit normaler Einfügung fertig werden. So kann ich meine Schleife vermeiden, aber ich kann die temporäre Tabelle nicht vermeiden.

tpower
quelle
6

Es hört sich so an, als würde die Link-Tabelle die Many: Many-Beziehung zwischen der Object-Tabelle und der Data-Tabelle erfassen.

Mein Vorschlag ist, eine gespeicherte Prozedur zum Verwalten der Transaktionen zu verwenden. Wenn Sie in die Objekt- oder Datentabelle einfügen möchten, führen Sie Ihre Einfügungen durch, holen Sie sich die neuen IDs und fügen Sie sie in die Verknüpfungstabelle ein.

Auf diese Weise bleibt Ihre gesamte Logik in einem einfach zu rufenden Sproc zusammengefasst.

Bob Probst
quelle
Warum hat dich noch niemand bewertet? Die gespeicherte Prozedur ist der naheliegende und beste Weg. Kombinieren Sie Ihre Antwort mit der Antwort von Joel Coehoorn und Sie erhalten die beste Antwort!
Rhyous
4

Wenn Sie möchten, dass die Aktionen mehr oder weniger atomar sind, würde ich sicherstellen, dass sie in eine Transaktion eingeschlossen werden. Auf diese Weise können Sie sicher sein, dass beide nach Bedarf passiert sind oder nicht.

Craig
quelle
2
Die Aktionen sind atomar, wenn sie in eine Transaktion eingeschlossen sind, nicht "mehr oder weniger" atomar. Was nicht unbedingt garantiert ist, ist der Grad der Isolation, sofern Sie dies nicht angeben.
Dave Markle
4

Sie können eine Ansicht erstellen, in der die für Ihre Einfügeanweisung erforderlichen Spaltennamen ausgewählt werden, einen INSTEAD OF INSERT-Trigger hinzufügen und in diese Ansicht einfügen.

devio
quelle
4

Ich möchte die Verwendung betonen

SET XACT_ABORT ON;

für die MSSQL-Transaktion mit mehreren SQL-Anweisungen.

Siehe: https://msdn.microsoft.com/en-us/library/ms188792.aspx Sie bieten ein sehr gutes Beispiel.

Der endgültige Code sollte also wie folgt aussehen:

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

Insert kann jeweils nur an einem Tisch ausgeführt werden. Mehrere Einfügungen müssen mehrere Anweisungen haben.

Ich weiß nicht, dass Sie eine Tabellenvariable durchlaufen müssen - können Sie nicht einfach eine Masseneinfügung in eine Tabelle und dann die Masseneinfügung in die andere Tabelle verwenden?

Übrigens - ich vermute, Sie meinen, Sie kopieren die Daten von Object_Table. sonst macht die frage keinen sinn.

Carlton Jenke
quelle
2

Bevor Sie in Oracle eine multitable Einfügung durchführen können, können Sie einen Trick verwenden, bei dem eine Einfügung in eine Ansicht mit einem INSTEAD OF-Trigger zum Ausführen der Einfügungen definiert wird. Kann dies in SQL Server durchgeführt werden?

David Aldridge
quelle
-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
quelle
Könnten Sie einige Erklärungen hinzufügen?
Kyll
-2

// wenn Sie dasselbe wie die erste Tabelle einfügen möchten

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

// oder wenn Sie bestimmte Teile der ersten Tabelle einfügen möchten

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

// Ich weiß, es sieht zu gut aus, um richtig zu sein, aber es funktioniert und Sie können weiterhin Abfragen hinzufügen, indem Sie einfach die ändern

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

Ich habe 17 Tabellen, in denen dies funktioniert hat.

Brion
quelle
Wenn mitten in den Einsätzen etwas schief geht? Ihre Beilagen sind unvollständig. richtig? Wenn ja, haben Sie eine Rollback-Funktion, um es zu behandeln? Wenn nicht, haben Sie ein Problem mit Ihrer Datenintegrität.
Deepcell
7
-1. Diese Antwort scheint MySQL-Methoden in PHP zu verwenden. Die Frage ist mit SQL und SQL Server gekennzeichnet , ohne dass MySQL oder PHP erwähnt werden.
mskfisher