SQL Server: возможно ли вставить в две таблицы одновременно?

StackOverflow https://stackoverflow.com/questions/175066

Вопрос

Моя база данных содержит три таблицы: Object_Table , Data_Table и Link_Table . Таблица ссылок содержит только два столбца: идентификатор записи объекта и идентификатор записи данных.

Я хочу скопировать данные из DATA_TABLE , где они связаны с одним указанным идентификатором объекта, и вставить соответствующие записи в Data_Table и Link_Table для другой заданный идентификатор объекта.

Я могу сделать это, выбрав переменную таблицы и выполнив две вставки для каждой итерации.

Это лучший способ сделать это?

Изменить . Я хочу избежать цикла по двум причинам: во-первых, я ленив и таблица цикла / температуры требует больше кода, чем больше кода, тем больше мест для ошибок и Вторая причина - это беспокойство по поводу производительности.

Я могу скопировать все данные за одну вставку, но как получить таблицу ссылок для ссылки на новые записи данных, где каждая запись имеет новый идентификатор?

Это было полезно?

Решение 3

Ниже описана ситуация, в которой я находился, с использованием табличных переменных.

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

Спасибо другому ответ , который указал мне на предложение OUTPUT, я могу продемонстрировать решение:

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

Оказывается, однако, что это не так просто в реальной жизни из-за следующей ошибки

  

предложение OUTPUT INTO не может быть включено   любая сторона (первичный ключ, внешний   ключ) отношения

Я все еще могу OUTPUT INTO временную таблицу и затем завершить ее обычной вставкой. Так что я могу избежать цикла, но не могу избежать временной таблицы.

Другие советы

В одном утверждении : нет.

В одной транзакции : да

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

Хорошая новость заключается в том, что приведенный выше код также гарантированно будет атомарным и может быть отправлен на сервер из клиентского приложения с одной строкой sql в одном вызове функции, как если бы он был заявление. Вы также можете применить триггер к одной таблице, чтобы получить эффект одной вставки. Однако в конечном итоге это все еще два оператора, и вы, вероятно, не хотите запускать триггер для каждой вставки.

Вам все еще нужны два оператора INSERT , но похоже, что вы хотите получить IDENTITY из первой вставки и использовать его во второй, и в этом случае вы возможно, вы захотите посмотреть OUTPUT или OUTPUT INTO : http://msdn.microsoft.com/en-us/library/ms177564.aspx

Звучит так, будто таблица ссылок фиксирует отношения многие: многие между таблицей объектов и таблицей данных.

Я предлагаю использовать хранимую процедуру для управления транзакциями. Если вы хотите вставить данные в таблицу объектов или данных, выполните вставки, получите новые идентификаторы и вставьте их в таблицу ссылок.

Это позволяет сохранить всю логику в одном простом для вызова sproc.

Если вы хотите, чтобы действия были более или менее атомарными, я бы обязательно включил их в транзакцию. Таким образом, вы можете быть уверены, что оба произошли или оба не произошли, как нужно.

Вы можете создать представление, выбрав имена столбцов, необходимые для оператора вставки, добавить триггер INSTEAD OF INSERT и вставить в это представление.

Я хочу подчеркнуть использование

SET XACT_ABORT ON;

для транзакции MSSQL с несколькими SQL-операторами.

См .: https://msdn.microsoft.com/en-us/ библиотека / ms188792.aspx Они дают очень хороший пример.

Итак, окончательный код должен выглядеть следующим образом:

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

Вставка может работать только на одном столе одновременно. Несколько вставок должны иметь несколько операторов.

Я не знаю, что вам нужно делать циклическое преобразование табличной переменной - вы не можете просто использовать массовую вставку в одну таблицу, а затем массовую вставку в другую?

Кстати, я предполагаю, что вы имеете в виду скопировать данные из Object_Table; в противном случае вопрос не имеет смысла.

Прежде чем выполнять множественную вставку в Oracle, вы могли бы использовать прием, включающий вставку в представление, для которого был определен триггер INSTEAD OF для выполнения вставок. Это можно сделать в 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

// если вы хотите вставить то же, что и в первую таблицу

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

// или если вы хотите вставить определенные части первой таблицы

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

// я знаю, что это выглядит слишком хорошо, чтобы быть правым, но это работает, и вы можете продолжать добавлять запросы, просто изменив

    "$qry"-number and number in @mysql_query($qry"")
<Ч>

У меня есть 17 таблиц, в которых это работало.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top