必须声明标量变量“@status”“用户定义的表类型”

Posted

技术标签:

【中文标题】必须声明标量变量“@status”“用户定义的表类型”【英文标题】:Must declare the scalar variable "@status" "User defined table type" 【发布时间】:2015-01-19 09:34:19 【问题描述】:

我正在使用用户定义的表格类型,如下所示。注意,请我动态生成我的查询字符串并在最后执行该字符串。您可能会注意到一些引号

      ALTER PROCEDURE MyPROC
        @phoneNo nvarchar(30) = null,
        @status dbo.StatusViewTableType READONLY

        AS 
        BEGIN
     if(@option = 1)
    begin
      set @sql = 'SELECT   c.id,c.name,c.NewIc,c.OldIc,c.Title,c.nationality,c.CreatedDate,c.companyNo,c.NonIc,c.Email
                        FROM    customer c WITH (NOLOCK)
                        left outer join
                        dbo.Address with(nolock) on c.id =  dbo.Address.CustomerID 
                        left outer join dbo.ContactNo on c.id=dbo.ContactNo.CustomerID
                        WHERE     (c.id > 0) and ('


        if @oldIC <>'' and @phoneNo=''
            set @sql = @sql + ' (oldic ='''+ @oldIC + ''' )or'

        if @newIC <>'' and @phoneNo=''
            set @sql = @sql + ' (newIC ='''+ @newIC + ''' )or'

        if @companyno <>'' and @phoneNo=''
            set @sql = @sql + ' (companyno ='''+ @companyno + ''' )or'

        if @nonic <>'' and @phoneNo=''
            set @sql = @sql + ' (nonic ='''+ @nonic + ''' )or'

        If @phoneNo <>'' and @oldIC = '' and @newIC = '' and @companyno = '' and @nonic ='' 
        begin
            set @sql ='SELECT     c.id,c.name,c.NewIc,c.OldIc,c.Title,c.nationality,c.CreatedDate,c.companyNo,c.NonIc,c.Email
        FROM         dbo.Customer WITH (NOLOCK) c INNER JOIN
                              dbo.ContactNo WITH (NOLOCK)  ON c.id = dbo.ContactNo.CustomerID
        where   ContactNo = '''+ @phoneNo + ''' and  dbo.ContactNo.Contactability in (SELECT s.status   from  ' + [@status] + '  AS s ) '
        end
        if  @phoneNo='' 
        begin
        set @sql = Left(@sql,Len(@sql)-2)
        set @sql = @sql + ')'
        set @sql = @sql + '  and ( dbo.Address.Contactable in (SELECT  s.status   from ' + [@status] + '   AS s) or  dbo.ContactNo.Contactability in (SELECT  s.status from ' + [@status] + ' AS s) )'
        end 
print @sql

exec (@sql)
end

结束

在我的后端代码中,我传递如下参数:

SqlConnection myConnection = null;
SqlCommand myCommand = null;
SqlDataReader myReader = null;
myConnection = new SqlConnection(connectionString);
myCommand = myConnection.CreateCommand();
myCommand.CommandText = "GETCUSTOMER";
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.CommandTimeout = 0;
SqlParameter parameter;

int l = ids.FirstOrDefault().Length;
if (ids.FirstOrDefault().Length > 0)

    if (useDataTable)
    
        parameter = myCommand.Parameters.AddWithValue("@status", CreateDataTable(ids));
    
    else
    
        parameter = myCommand.Parameters.AddWithValue("@status", CreateSqlDataRecords(ids));
    

    parameter.SqlDbType = SqlDbType.Structured;
    parameter.TypeName = "dbo.StatusViewTableType";   


myCommand.Parameters.Add(new SqlParameter("@phoneNo", SqlDbType.NVarChar));    
myCommand.Parameters["@phoneNo"].Value = phoneNo;

我遇到了参数@status 的问题。它在存储过程中无法识别。

抛出异常:

必须声明标量变量“@status”。

下面是我的StatusViewTAbleType

CREATE TYPE [dbo].[StatusViewTableType] AS TABLE(
    [Status] [int] NOT NULL
)
GO

任何帮助将不胜感激。

【问题讨论】:

在进行进一步更改之前,请查看我对您的帖子所做的所有编辑。以尽可能最好的方式提出您的问题始终是一个好习惯,否则他们将不会受到好评。我花了几分钟时间为您格式化问题,因此回滚了您的编辑,因此请根据我的编辑重新应用您的更改。 对不起先生,我的 cquery 是动态生成的。像上面一样。 【参考方案1】:

如果您在完全限定的对象名称中使用表值参数,则必须将其括在方括号中,即应该使用 @Status.status 而不是 [@Status].status 或使用别名。

您可以非常简单地重新创建它:

DECLARE @P TABLE (ID INT);
SELECT @P.ID FROM @P;

哪个会引发错误:

必须声明标量变量“@P”。

我也不认为你正确使用了参数,我认为你的程序应该是:

ALTER PROCEDURE MyPROC
    @phoneNo nvarchar(30) = NULL,
    @status dbo.StatusViewTableType READONLY

AS 
BEGIN
    SELECT    * 
    FROM    dbo.Customer WITH (NOLOCK)  
            INNER JOIN dbo.ContactNo WITH (NOLOCK)  
                ON dbo.Customer.id = dbo.ContactNo.CustomerID
    WHERE   ContactNo = @phoneNo
    AND     dbo.ContactNo.Contactability IN (SELECT s.status FROM @status AS s);

END 

最后,我会强烈反对using SELECT * in production code


编辑

关于您的动态 SQL 问题,请使用sp_executesql,这将允许您使用参数,所以不要使用类似:

DECLARE @SQL NVARCHAR(MAX) = 'SELECT A, B, C FROM T WHERE 1 = 1',
        @P NVARCHAR(10) = 'X';
IF @P <> '' 
    SET @SQL = @SQL + ' AND A = ''' + @P + '''';
    
EXEC(@SQL);

你会使用

DECLARE @SQL NVARCHAR(MAX) = 'SELECT A, B, C FROM T WHERE 1 = 1',
        @P NVARCHAR(10) = 'X';
IF @P <> '' 
    SET @SQL = @SQL + ' AND A = @P';
    
EXECUTE sp_executesql @SQL, N'@P NVARCHAR(10), @P;

所以您将@P 作为参数传递给查询。这应该可以解决您所有的单引号问题

【讨论】:

@Gareth 先生请问我如何在一个 sql 字符串中实现这一点,就像我上面的程序中的那样。我真的很难接受。 @MR gareth。它看起来像我正在寻找的 sp_executesql。但是,当我运行它的询问 @statement 参数时,它不存在。请你帮我处理我的参数 .@id bigint = 0, @oldIC nvarchar(200) = '', @newIC nvarchar(200) = '', @companyno nvarchar(100) = '', @nonic nvarchar(100) = '', @phoneNo nvarchar(100) = '', @option int = 0, @sql nvarchar(1000) = null, @status dbo.StatusViewTableType READONLY .?【参考方案2】:

问题是您使用了不需要的单引号。试试这个。

ALTER PROCEDURE Myproc @phoneNo NVARCHAR(30) = NULL,
                       @status  dbo.STATUSVIEWTABLETYPE READONLY
AS
  BEGIN
      SELECT *
      FROM   dbo.Customer WITH (NOLOCK)
             INNER JOIN dbo.ContactNo WITH (NOLOCK)
                     ON dbo.Customer.id = dbo.ContactNo.CustomerID
      WHERE  ContactNo = @phoneNo
             AND dbo.ContactNo.Contactability IN (SELECT status
                                                  FROM   @status)
  END 

【讨论】:

对不起,先生,不得不提到。单引号的原因是我的查询是动态创建的。请再次查看我的过程。 @NuruSalihu - 正如 garethD 所提到的,您需要用括号将@status 括起来,例如..select [@Status].status from.. 好的,我现在正在尝试。 tq 我得到无效的列名 [@status]。请我动态生成查询字符串,然后在最后执行该字符串。【参考方案3】:

Dynamic SQL 无法识别超出其范围的变量。这就是它出错的原因。

【讨论】:

以上是关于必须声明标量变量“@status”“用户定义的表类型”的主要内容,如果未能解决你的问题,请参考以下文章

必须声明标量变量@Id?

表变量和错误“必须声明标量变量”

不正确的语法必须声明标量变量

例外 |必须声明标量变量@IdAlbum

查询“必须声明标量变量”

Dapper:必须在 Select 命令中声明标量变量