Первое, на что мне нужно обратить внимание, это то, что таблица поиска, подобная этой, должна , а не иметь столбец с автоматическим номером (IDENTITY
). Значения автонумерации syntheti c и должны использоваться только тогда, когда вам все равно , что это за значение, только то, что оно уникально. Это хорошо работает, когда пользователи могут добавлять значения в набор поиска.
Для таблиц поиска, не обслуживаемых пользователем, таких как VehicleType
, вам do все равно, какие значения VehicleTypeId
так что авто-номер работает против вас. Если вы можете удалить свойство IDENTITY
из определения столбца, вам абсолютно необходимо. Если вы не можете, вы застряли, используя IDENTITY_INSERT
. Только не забудьте использовать IDENTITY
в будущих конструкциях справочных таблиц.
Есть способ сделать это без табличной переменной: используйте CTE с оператором MERGE
.
CTE будет содержать все значения, которые вы хотите использовать, используя объединенные операторы stati c SELECT
(использование UNION ALL
пропускает повторные проверки, поскольку вы знаете, что дубликатов не будет). Оператор MERGE
использует CTE в качестве исходной таблицы.
Предложение ON
в операторе MERGE
должно сравнивать только первичный ключ. Если значение в неключевом столбце было изменено, это приведет к вставке новой строки; новый ряд будет нарушать первичный ключ. Вместо этого обновите столбец Name
до значения в CTE. Для этого я добавил ниже предложение WHEN MATCHED
.
Я предлагаю всегда использовать dst
и src
в качестве псевдонимов в выражении MERGE
. Оператор MERGE
может включать много разных частей. Если вы используете одинаковые псевдонимы для исходных и целевых / целевых таблиц, вам придется беспокоиться об одной меньшей сложности. Я видел, что это на самом деле помогает разработчикам изучать синтаксис и эту технику.
Мне нравится называть CTE src
, поэтому мне не нужно его псевдонимом.
-- Only IF you cannot remove the IDENTITY property from VehicleTypeId:
SET IDENTITY_INSERT [dbo].[VehicleType] ON;
GO
-- Stage the data and merge it into the table in one shot:
WITH [src] ([VehicleTypeId], [Name])
AS
(
SELECT 1, 'Automobile'
UNION ALL SELECT 2, 'HeavyVehicle'
UNION ALL SELECT 3, 'Motorcycle'
)
MERGE INTO [dbo].[VehicleType] AS [dst]
USING [src]
ON [dst].[VehicleTypeId] = src.[VehicleTypeId]
WHEN NOT MATCHED BY TARGET THEN
INSERT ([VehicleTypeId], [Name])
VALUES ([src].[VehicleTypeId], [src].[Name])
WHEN MATCHED AND ([dst].[Name] <> [src].[Name]) THEN
UPDATE
SET [Name] = [src].[Name]
;
GO
-- Again, only IF you cannot remove the IDENTITY property from VehicleTypeId:
SET IDENTITY_INSERT [dbo].[VehicleType] OFF;
GO
Когда я пишу такой сценарий, который намереваюсь запустить из SSMS, я включаю предложение OUTPUT
, чтобы увидеть, что произошло, и убедиться, что оно было правильным.
...
OUTPUT $action AS [*Action],
COALESCE([inserted].[VehicleTypeId], [deleted].[VehicleTypeId]) AS [=VehicleTypeId],
[deleted].[Name] AS [-Name],
[inserted].[Name] AS [+Name]
-- Repeat deleted and inserted AS -/+ for remaining non-key columns.
;
Примечание о префиксах, которые я Вы использовали псевдонимы:
*
для столбцов метаданных (на самом деле, это только когда-либо *Action
). =
для столбцов первичного ключа. Они не изменятся, поэтому только один на столбец в ключе. -
для старых значений (например, -Name
). +
для новых значений (например, +Name
).