SQL Server: возможно ли вставить в две таблицы одновременно?
-
05-07-2019 - |
Вопрос
Моя база данных содержит три таблицы: 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 таблиц, в которых это работало.