必须声明 table 变量“@TempTable”
Must declare the table variable "@TempTable"
我想添加一个脚本post-部署来插入数据。但是当我在下面执行这个脚本时,我收到了这条消息错误:
Must declare the table variable "@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
我需要指出的第一件事是像这样的查找 table 应该 而不是 有一个自动编号 (IDENTITY
)柱子。自动编号值是 合成的,仅当您不关心值是什么时才应使用,只关心它是唯一的。当用户可以将值添加到查找集时,这很有效。
对于非用户可服务的查找 table,就像您的 VehicleType
,您 做 关心 VehicleTypeId
值是什么自动编号对你不利。如果您可以从列定义中删除 IDENTITY
属性,您绝对应该这样做。如果不能,您将无法使用 IDENTITY_INSERT
。请记住不要在以后的查找 table 设计中使用 IDENTITY
。
有一种方法可以在没有 table 变量的情况下执行此操作:使用带有 MERGE
语句的 CTE。
CTE 将包含您使用联合静态 SELECT
语句所需的所有值(使用 UNION ALL
会跳过重复检查,因为您知道不会有任何重复项)。
MERGE
语句使用 CTE 作为其来源 table.
MERGE
语句中的ON
子句应该只比较主键。如果更改了非键列中的值,则会导致插入新行;新行将违反主键。相反,将 Name
列更新为 CTE 中的值。为此,我在下面添加了一个 WHEN MATCHED
子句。
我建议在 MERGE
语句中始终使用 dst
和 src
作为别名。 MERGE
语句可以涉及很多不同的部分。如果您对源和 target/destination table 使用相同的别名,那么您不必担心的复杂性就会降低一点。我已经看到这实际上可以帮助开发人员学习语法和这项技术。
我喜欢将 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
)。
我想添加一个脚本post-部署来插入数据。但是当我在下面执行这个脚本时,我收到了这条消息错误:
Must declare the table variable "@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
我需要指出的第一件事是像这样的查找 table 应该 而不是 有一个自动编号 (IDENTITY
)柱子。自动编号值是 合成的,仅当您不关心值是什么时才应使用,只关心它是唯一的。当用户可以将值添加到查找集时,这很有效。
对于非用户可服务的查找 table,就像您的 VehicleType
,您 做 关心 VehicleTypeId
值是什么自动编号对你不利。如果您可以从列定义中删除 IDENTITY
属性,您绝对应该这样做。如果不能,您将无法使用 IDENTITY_INSERT
。请记住不要在以后的查找 table 设计中使用 IDENTITY
。
有一种方法可以在没有 table 变量的情况下执行此操作:使用带有 MERGE
语句的 CTE。
CTE 将包含您使用联合静态 SELECT
语句所需的所有值(使用 UNION ALL
会跳过重复检查,因为您知道不会有任何重复项)。
MERGE
语句使用 CTE 作为其来源 table.
MERGE
语句中的ON
子句应该只比较主键。如果更改了非键列中的值,则会导致插入新行;新行将违反主键。相反,将 Name
列更新为 CTE 中的值。为此,我在下面添加了一个 WHEN MATCHED
子句。
我建议在 MERGE
语句中始终使用 dst
和 src
作为别名。 MERGE
语句可以涉及很多不同的部分。如果您对源和 target/destination table 使用相同的别名,那么您不必担心的复杂性就会降低一点。我已经看到这实际上可以帮助开发人员学习语法和这项技术。
我喜欢将 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
)。