必须声明表变量“ @TempTable”

问题描述 投票:0回答:1

我想在部署后添加脚本以插入数据。但是当我在下面执行此脚本时,出现此消息错误:

必须声明表变量“ @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
c# sql-server tsql dacpac
1个回答
0
投票

我需要指出的第一件事是,这样的查找表应该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语句中始终使用srcMERGE作为别名。 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)。
© www.soinside.com 2019 - 2024. All rights reserved.