Pregunta

Mi base de datos contiene tres tablas llamadas Object_Table , Data_Table y Link_Table . La tabla de enlaces solo contiene dos columnas, la identidad de un registro de objeto y la identidad de un registro de datos.

Quiero copiar los datos de DATA_TABLE donde está vinculado a una identidad de objeto dada e insertar los registros correspondientes en Data_Table y Link_Table para una identidad de objeto dada diferente.

Yo puedo hacer esto seleccionando en una variable de tabla y haciendo un ciclo haciendo dos inserciones para cada iteración.

¿Es esta la mejor manera de hacerlo?

Editar : quiero evitar un bucle por dos razones, la primera es que soy perezoso y que una tabla de temp / bucle requiere más código, más código significa más lugares para cometer un error y La segunda razón es la preocupación por el rendimiento.

Puedo copiar todos los datos en una inserción, pero ¿cómo puedo hacer que la tabla de enlaces se vincule con los nuevos registros de datos donde cada registro tiene una nueva identificación?

¿Fue útil?

Solución 3

Lo siguiente configura la situación que tuve, usando variables de tabla.

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

Gracias a otro respuesta que me indicó la cláusula de SALIDA que puedo demostrar una solución:

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

Sin embargo, resulta que no es tan simple en la vida real debido al siguiente error

  

la cláusula OUTPUT INTO no puede estar activada   cualquier lado de una (clave primaria, extranjera   clave) relación

Todavía puedo SALTAR EN una tabla temporal y luego terminar con la inserción normal. Así que puedo evitar mi bucle pero no puedo evitar la tabla temporal.

Otros consejos

En una declaración : No.

En una transacción : Sí

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

La buena noticia es que también se garantiza que el código anterior sea atómico , y se puede enviar al servidor desde una aplicación cliente con una cadena de SQL en una sola función de llamada como si fuera una. declaración. También puede aplicar un disparador a una tabla para obtener el efecto de una sola inserción. Sin embargo, en última instancia, aún son dos afirmaciones y probablemente no desee ejecutar el desencadenante para cada inserción.

Aún necesita dos declaraciones INSERT , pero parece que desea obtener el IDENTITY de la primera inserción y utilizarlo en la segunda, en cuyo caso, podría querer ver OUTPUT o OUTPUT INTO : http://msdn.microsoft.com/en-us/library/ms177564.aspx

Parece que la tabla de enlaces captura la relación muchos: muchos entre la tabla de objetos y la tabla de datos.

Mi sugerencia es utilizar un procedimiento almacenado para gestionar las transacciones. Cuando desee insertarlo en la tabla Objeto o Datos, realice las inserciones, obtenga los nuevos ID e insértelos en la tabla de enlaces.

Esto permite que toda tu lógica permanezca encapsulada en un sproc fácil de llamar.

Si desea que las acciones sean más o menos atómicas, me aseguraré de incluirlas en una transacción. De esa manera, puede estar seguro de que ambos sucedieron o que no sucedieron cuando fue necesario.

Puede crear una Vista seleccionando los nombres de columna requeridos por su declaración de inserción, agregar un Desencadenador INSTEAD OF INSERT e insertarlo en esta vista.

Quiero hacer hincapié en el uso

SET XACT_ABORT ON;

para la transacción MSSQL con varias sentencias de SQL.

Consulte: https://msdn.microsoft.com/en-us/ library / ms188792.aspx Son un buen ejemplo.

Por lo tanto, el código final debe ser similar al siguiente:

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

El inserto solo puede operar en una tabla a la vez. Las inserciones múltiples deben tener varias declaraciones.

No sé si necesita hacer el bucle a través de una variable de tabla. ¿No puede simplemente usar una inserción masiva en una tabla y luego la inserción masiva en la otra?

Por cierto, supongo que te refieres a copiar los datos de Object_Table; de lo contrario la pregunta no tiene sentido.

Antes de poder realizar una inserción multitable en Oracle, podría usar un truco que involucra una inserción en una vista que tenía un activador INSTEAD OF definido para realizar las inserciones. ¿Se puede hacer esto en 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

// si desea insertar lo mismo que en la primera tabla

$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 si desea insertar ciertas partes de la tabla 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);

// Sé que parece demasiado bueno para estar en lo cierto, pero funciona y puedes seguir agregando consultas simplemente cambiando el

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

Tengo 17 tablas en las que ha funcionado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top