Domanda

Il mio database contiene tre tabelle denominate Object_Table , Data_Table e Link_Table . La tabella dei collegamenti contiene solo due colonne, l'identità di un record di oggetto e un'identità di un record di dati.

Voglio copiare i dati da DATA_TABLE dove sono collegati a una determinata identità dell'oggetto e inserire i record corrispondenti in Data_Table e Link_Table per una diversa identità dell'oggetto data.

Posso posso farlo selezionando in una variabile di tabella e il ciclo attraverso due inserimenti per ogni iterazione.

È questo il modo migliore per farlo?

Modifica : voglio evitare un loop per due motivi, il primo è che sono pigro e una tabella loop / temp richiede più codice, più codice significa più luoghi in cui fare un errore e la seconda ragione è una preoccupazione per le prestazioni.

Posso copiare tutti i dati in un solo inserto, ma come posso fare in modo che la tabella dei collegamenti si colleghi ai nuovi record di dati in cui ogni record ha un nuovo ID?

È stato utile?

Soluzione 3

Quanto segue imposta la situazione che ho avuto, usando le variabili di tabella.

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

Grazie a un altro risposta che mi ha indicato la clausola OUTPUT che posso dimostrare una soluzione:

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

Si scopre tuttavia che non è così semplice nella vita reale a causa del seguente errore

  

la clausola OUTPUT INTO non può essere attivata   entrambi i lati di una (chiave primaria, esterna   chiave) relazione

Posso ancora OUTPUT INTO una tabella temporanea e quindi finire con l'inserimento normale. Quindi posso evitare il mio ciclo ma non posso evitare la tabella temporanea.

Altri suggerimenti

In una dichiarazione : No.

In una transazione : Sì

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

La buona notizia è che il codice sopra riportato è garantito anche come atomico e può essere inviato al server da un'applicazione client con una stringa sql in una singola chiamata di funzione come se fosse una dichiarazione. È inoltre possibile applicare un trigger a una tabella per ottenere l'effetto di un singolo inserimento. Tuttavia, in definitiva sono ancora due affermazioni e probabilmente non si desidera eseguire il trigger per ogni inserto.

Hai ancora bisogno di due istruzioni INSERT , ma sembra che tu voglia ottenere IDENTITY dal primo inserto e usarlo nel secondo, nel qual caso, tu potrebbe essere utile esaminare OUTPUT o OUTPUT INTO : http://msdn.microsoft.com/en-us/library/ms177564.aspx

Sembra che la tabella Link catturi le molte: molte relazioni tra la tabella Object e la tabella Data.

Il mio suggerimento è di utilizzare una procedura memorizzata per gestire le transazioni. Quando si desidera inserire nella tabella Oggetto o Dati eseguire gli inserimenti, ottenere i nuovi ID e inserirli nella tabella Collegamento.

Ciò consente a tutta la tua logica di rimanere incapsulata in uno sproc facile da chiamare.

Se vuoi che le azioni siano più o meno atomiche, mi assicurerei di includerle in una transazione. In questo modo puoi essere sicuro che entrambi siano accaduti o che entrambi non siano avvenuti secondo necessità.

È possibile creare una vista selezionando i nomi delle colonne richiesti dall'istruzione insert, aggiungere un trigger INSTEAD OF INSERT e inserire in questa vista.

Voglio sottolineare l'uso di

SET XACT_ABORT ON;

per la transazione MSSQL con più istruzioni sql.

Vedi: https://msdn.microsoft.com/en-us/ biblioteca / ms188792.aspx Forniscono un ottimo esempio.

Quindi, il codice finale dovrebbe essere simile al seguente:

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

Inserisci può funzionare solo su una tabella alla volta. Gli inserti multipli devono avere più istruzioni.

Non so che devi fare il ciclo attraverso una variabile di tabella - non puoi semplicemente usare un inserto di massa in una tabella, quindi l'inserto di massa nell'altra?

A proposito - Immagino che intendi copiare i dati da Object_Table; altrimenti la domanda non ha senso.

Prima di poter eseguire un inserimento multitable in Oracle, è possibile utilizzare un trucco che coinvolge un inserimento in una vista in cui è stato definito un trigger INSTEAD OF per eseguire gli inserimenti. Questo può essere fatto in SQL Server?

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

// se si desidera inserire lo stesso della prima tabella

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

// o se si desidera inserire determinate parti della tabella uno

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

// So che sembra troppo bello per essere giusto, ma funziona e puoi continuare ad aggiungere query basta cambiare

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

Ho 17 tavoli in cui ha funzionato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top