Самый простой (и, вероятно, самый эффективный) способ - вставить непосредственно в целевую таблицу MyTable
без промежуточной промежуточной таблицы. Я бы использовал параметр табличного значения, чтобы передать таблицу значений в вашу хранимую процедуру.
https://docs.microsoft.com/en-us/sql/relational-databases/tables/use-table-valued-parameters-database-engine?view=sql-server-2017
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters
Если вы действительно хотите использовать промежуточную таблицу, вы не можете полагаться на порядок строк, возвращаемых предложением OUTPUT
. Вам необходимо сохранить явное отображение между #MyTableStaging.RowOrder
и сгенерированным MyTable.Id
. Когда вы используете выражение OUTPUT
в простом операторе INSERT
, вы не можете включать столбцы из исходной таблицы в вывод. Есть обходной путь. Вы можете использовать MERGE
вместо предложений INSERT
и OUTPUT
оператора MERGE
, разрешающих столбцы из исходной таблицы.
См. Очень похожий вопрос Объединить OUTPUT вставки.id со значением из выбранной строки
MERGE
может INSERT
, UPDATE
и DELETE
строк. В нашем случае нам нужно всего лишь INSERT
.
1=0
всегда ложно, поэтому часть NOT MATCHED BY TARGET
всегда выполняется.
В общем, могут быть и другие ветки, см. Документы.
WHEN MATCHED
обычно используется для UPDATE
;
WHEN NOT MATCHED BY SOURCE
обычно используется для DELETE
, но они нам здесь не нужны.
Эта запутанная форма MERGE
эквивалентна простой INSERT
,
но в отличие от простого INSERT
его предложение OUTPUT
позволяет ссылаться на нужные нам столбцы.
Он позволяет извлекать столбцы из исходной и целевой таблиц, сохраняя соответствие между старым и новым идентификаторами.
DECLARE @MyTableOutput TABLE
(
OldRowOrder int NOT NULL
,NewID UNIQUEIDENTIFIER NOT NULL
);
MERGE INTO dbo.MyTable
USING
(
SELECT RowOrder, SomeNonUniqueValue
FROM #MyTableStaging
) AS Src
ON 1 = 0
WHEN NOT MATCHED BY TARGET THEN
INSERT (SomeNonUniqueValue)
VALUES (Src.SomeNonUniqueValue)
OUTPUT Src.RowOrder AS OldRowOrder, inserted.ID AS NewID
INTO @MyTableOutput(OldRowOrder, NewID)
;
Если ваш администратор БД так боится MERGE
, вам не нужно его использовать. Хотя это будет менее эффективно.
Просто вставьте все строки.
INSERT INTO dbo.MyTable (SomeNonUniqueValue)
SELECT SomeNonUniqueValue
FROM #MyTableStaging
;
Нам нет дела до заказа.
Если бы SomeNonUniqueValue
были уникальными, вы можете просто присоединиться к этому столбцу, чтобы сопоставить RowOrder
с Id
. Поскольку эти значения не являются уникальными, нам потребуется дополнительный шаг и сгенерировать уникальные номера строк для объединения.
WITH
CTE_Dst
AS
(
SELECT
Id
,SomeNonUniqueValue
,ROW_NUMBER() OVER (ORDER BY SomeNonUniqueValue) AS rn
FROM dbo.MyTable
)
,CTE_Src
AS
(
SELECT
RowOrder
,SomeNonUniqueValue
,ROW_NUMBER() OVER (ORDER BY SomeNonUniqueValue) AS rn
FROM #MyTableStaging
)
SELECT
CTE_Dst.Id
,CTE_Src.RowOrder
FROM
CTE_Dst
INNER JOIN CTE_Src ON CTE_Src.rn = CTE_Dst.rn
;
Если у вас есть, скажем, три строки с одинаковым SomeNonUniqueValue
, на самом деле не имеет значения, как вы отображаете эти строки вместе, потому что SomeNonUniqueValue
- это то же самое.
Пример:
#MyTableStaging
+----------+--------------------+
| RowOrder | SomeNonUniqueValue |
+----------+--------------------+
| 1 | qwerty |
| 2 | qwerty |
| 3 | qwerty |
| 4 | asdf |
| 5 | asdf |
+----------+--------------------+
MyTable
+----+--------------------+
| ID | SomeNonUniqueValue |
+----+--------------------+
| A | qwerty |
| B | qwerty |
| C | qwerty |
| D | asdf |
| E | asdf |
+----+--------------------+
Вы можете отобразить их так:
+----------+----+--------------------+
| RowOrder | ID | SomeNonUniqueValue |
+----------+----+--------------------+
| 1 | A | qwerty |
| 2 | B | qwerty |
| 3 | C | qwerty |
| 4 | D | asdf |
| 5 | E | asdf |
+----------+----+--------------------+
Или вы можете отобразить их так:
+----------+----+--------------------+
| RowOrder | ID | SomeNonUniqueValue |
+----------+----+--------------------+
| 1 | B | qwerty |
| 2 | C | qwerty |
| 3 | A | qwerty |
| 4 | E | asdf |
| 5 | D | asdf |
+----------+----+--------------------+
Это все еще допустимое отображение, потому что все три значения qwerty
одинаковы. Ни одно из этих сопоставлений не является «более правильным», чем другое.
Очевидно, что если ваш MyTable
не был пустым до INSERT
, вам нужно выбрать только новые строки.