我想在部署后添加脚本以插入数据。但是当我在下面执行此脚本时,出现此消息错误:
必须声明表变量“ @TempTable”。
此脚本的目的是强制添加作为主键的Id,我知道我们可以使用:
SET IDENTITY_INSERT [dbo].[TableName] ON;
GO
和合并后
SET IDENTITY_INSERT [dbo].[TableName] OFF;
GO
但是它对我不起作用,我无法部署我的DacPac
DECLARE @vehicleType TABLE(
[VehicleTypeId] BIGINT,
[Name] NVARCHAR(200) NOT NULL
);
INSERT INTO @VehicleType ([VehicleTypeId], [Name])
VALUES(1,'Automobile'),(2,'HeavyVehicle'),(3,'Motorcycle')
SET IDENTITY_INSERT [dbo].[VehicleType] ON;
GO
MERGE INTO [dbo].[VehicleType]
USING @VehicleType as vhlt
ON ([dbo].[VehicleType].[VehicleTypeId] = vhtl.[VehicleTypeId] and [dbo].[VehicleType].[Name] = vhlt.[Name])
WHEN NOT MATCHED THEN
INSERT VALUES ([VehicleTypeId], [Name]);
SET IDENTITY_INSERT [dbo].[VehicleType] OFF;
GO
我需要指出的第一件事是,这样的查找表应该not具有自动编号(IDENTITY
)列。自动编号值是synthetic,仅当您do n't care值是唯一的时才应使用。当用户可以向查找集中添加值时,这种方法效果很好。
对于不可用户使用的查找表,例如VehicleType
,您do关心VehicleTypeId
的值是什么,因此自动编号对您不利。如果可以从列定义中删除IDENTITY
属性,则绝对应该这样做。如果不能,则无法使用IDENTITY_INSERT
。只要记住不要在将来的查找表设计中使用IDENTITY
。
没有表变量就可以做到这一点:在MERGE
语句中使用CTE。
CTE将包含使用联合静态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
)。