将用户定义的表类型与生成的数据库部署脚本一起使用时出现问题

Posted

技术标签:

【中文标题】将用户定义的表类型与生成的数据库部署脚本一起使用时出现问题【英文标题】:Problem using user-defined table type with generated database deployment script 【发布时间】:2011-08-20 17:27:28 【问题描述】:

我遇到了一个奇怪的问题,VS2010 的数据库项目无法执行生成的部署脚本,该脚本在 SP 的参数列表中使用用户定义的表类型。执行部署脚本时出现以下错误:

错误 SQL01268:.Net SqlClient 数据提供者:消息 137,级别 16,状态 1,过程 AppSearch,第 36 行必须声明标量变量“@platforms”。

这里的@platforms变量是用户定义的表类型,简单定义如下:

CREATE TYPE [dbo].[IdList] AS TABLE 
(
    Id      uniqueidentifier
);

我正在创建的存储过程如下所示,它使用 UDDT 作为其参数之一:

PRINT N'Creating [dbo].[AppSearch]...';


GO
CREATE PROCEDURE [dbo].[AppSearch]
    @nameContains           nvarchar(30),
    @descriptionContains    nvarchar(max),
    @isEditorsPick          bit,
    @dateAddedStart         datetime,
    @dateAddedEnd           datetime,
    @platforms              IdList      readonly
AS
begin
    select
        l.Id as [LibraryId],
        l.Name as [LibraryName],
        l.Description as [LibraryDescription],
        c.Id as [CategoryId],
        c.Name as [CategoryName],
        c.Description as [CategoryDescription],
        a.Id as [AppId],
        a.Name as [AppName],
        a.Description as [AppDescription],
        a.IsEditorsPick as [AppIsEditorsPick],
        a.DateAdded as [AppDateAdded],
        p.Id as [PlatformId],
        p.Name as [PlatformName],
        p.Architecture as [PlatformArchitecture]
    from
        Library l
        inner join Category c               on l.Id = c.ParentLibraryId
        inner join App a                    on c.Id = a.ParentCategoryId
        inner join AppSupportedPlatform px  on a.Id = px.AppId
        inner join Platform p               on px.PlatformId = p.Id
    where
            (@nameContains is not null and a.Name like '%' + @nameContains + '%')
        and (@descriptionContains is not null and a.Description like '%' + @descriptionContains + '%')
        and (@isEditorsPick is not null and a.IsEditorsPick = @isEditorsPick)
        and (@dateAddedStart is not null and @dateAddedEnd is not null and a.DateAdded between @dateAddedStart and @dateAddedEnd)
        and (@platforms is not null and p.Id in (select Id from @platforms))
end
GO

部署脚本使用 SQLCMD 模式执行。关于我为什么会收到上述错误的任何想法?

提前致谢!

【问题讨论】:

我想通了。在我的脚本快结束时,我检查@platforms 是否不为空,结果我无法进行该检查,因为它不是标量变量。我应该更多地注意错误信息,大声笑。每日一课:TVP 不是标量变量。 【参考方案1】:

考虑一下表格类型应该有点像表格。你不能说“如果 TABLE 不是 NULL”,那么为什么你可以说“如果 TABLE TYPE 不是 NULL”呢?我没有广泛使用 TVP,但是如何检查 TVP 是否为空:

AND (EXISTS (SELECT 1 FROM @platforms) AND p.Id IN (SELECT Id FROM @platforms));

后者可能就足够了(同样,这更多是因为缺乏玩 TVP 而不是任何东西)或者也许:

AND (p.Id IN (SELECT Id FROM @platforms) OR NOT EXISTS (SELECT 1 FROM @platforms));

【讨论】:

感谢您的回答。我刚才才想通。 UDDT 不是标量类型,因此“不为空”检查无效,因为它需要标量类型。我认为我什至不需要检查 @platforms 变量,所以我只是删除了它(现在)。 您是否需要它取决于在没有该参数的情况下调用存储过程时您想要的行为。如果你只是说AND p.Id IN (SELECT Id FROM @platforms),当它为空时你想发生什么?您想要忽略检查还是想要 0 个结果? 我希望支票实际上被忽略。感谢您的输入。非常感谢。

以上是关于将用户定义的表类型与生成的数据库部署脚本一起使用时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

发布脚本以仅部署特定的已定义表/存储过程/函数

将自己的自定义表单与 MailChimp 一起使用 [关闭]

EF Core 使用许多用户定义的表类型执行过程

以编程方式为用户定义的数据类型 (UDDT) 生成 DDL 语句

如何在SQL Server中使用用户定义的表类型插入数据时避免重复记录

使用多个表源合并(用户定义的表类型和输入参数)