【问题标题】:Sql Error Must declare the scalar variable , even after declaring variableSql 错误必须声明标量变量,即使在声明变量之后
【发布时间】:2013-01-16 11:44:45
【问题描述】:

即使我使用[GetAllProductById] 6,0,0,0,'A122',我在下方查询并收到错误Must declare the scalar variable "@collectionId"

ALTER proc [dbo].[GetAllProductById] 
(
    @collectionId int,
    @GrandId int  ,
    @ParentId int ,
    @ChildId int,
    @dealerid varchar(50) 
)
As
Begin

Declare @sql as varchar(max)
 -- In case dealer is logged in ,then calculate the Discounted amount and return the same,
    -- else return Mrp and Our Price for all other customers

    IF  @collectionid<=0

        BEGIN
            IF @dealerid<>''
                BEGIN
                    SET @sql = '    Select Top(5) Product.Id,ProdImage,ProductCode, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((Product.BasicPrice + ValueAdd),0), 
                                          Discounted = ISNULL((Select (Product.BasicPrice + (ValueAdd -(ValueAdd *(Discount*0.01))))
                                                 From DealerDiscount 
                                                 Where CategoryId = Product.GrandCategoryId AND DealerId='+@dealerid+'),0)
                                    From Product  Where 1=1 ';
                END
             ELSE
                BEGIN
                    SET @sql = '    Select Top(5) Id,ProdImage,ProductCode, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((BasicPrice + ValueAdd),0), Discounted=0 
                                    From Product
                                    Where 1=1 ';
                END 

        END
    ELSE
        BEGIN
            IF @dealerid<>''
                BEGIN
                    SET @sql = '    Select  Product.Id,ProdImage,ProductCode,Collections.Name,Collections.Id, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((Product.BasicPrice + ValueAdd),0), 
                                          Discounted = ISNULL((Select (Product.BasicPrice + (ValueAdd -(ValueAdd *(Discount*0.01))))
                                                 From DealerDiscount 
                                                 Where CategoryId = Product.GrandCategoryId AND DealerId='+@dealerid+'),0)
                                    FROM    Collections INNER JOIN
                                            Product ON Collections.Id = Product.CollectionId 
                                            where Product.CollectionId=@collectionId   AND 1=1 ';
                END
             ELSE
                BEGIN
                    SET @sql = '    Select  Product.Id,ProdImage,Collections.Name,Collections.Id,ProductCode, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((BasicPrice + ValueAdd),0), Discounted=0 
                                    FROM    Collections INNER JOIN
                                            Product ON Collections.Id = Product.CollectionId 
                                            where Product.CollectionId=@collectionId AND 1=1 ';
                END 

            if (@GrandId > 0 and @ParentId>0 and @ChildId > 0 and @collectionId=0)
                Begin
                    Set @sql  = @sql + ' Product.ParentCategoryId = '+ Convert(Varchar, @ParentId)+' AND Product.GrandCategoryId = '+ Convert(Varchar, @GrandId)+' AND Product.ChitdCategoryId = '+Convert(varchar,@ChildId);
                End
            if (@GrandId > 0 and @ParentId>0 and @ChildId = 0 and @collectionId=0)
                Begin
                    Set @sql  = @sql + ' Product.ParentCategoryId = '+ Convert(Varchar, @ParentId)+' AND Product.GrandCategoryId = '+ Convert(Varchar, @GrandId)
                End
            if (@GrandId > 0 and @ParentId=0 and @ChildId = 0 and @collectionId=0)
                Begin
                    Set @sql  = @sql + ' AND Product.GrandCategoryId = '+ Convert(Varchar, @GrandId)
                End
        END

        exec(@sql)

END   

【问题讨论】:

    标签: .net sql sql-server-2008 tsql


    【解决方案1】:

    与其将值连接到 TSQL 中,不如修改当前代码以在生成的 TSQL 中使用 sp_executesql参数,这样可以避免在生成的 TSQL 中注入 SQL 的风险,并允许查询计划重用。例如:

    SET @sql = '    Select Top(5) Product.Id,ProdImage,ProductCode, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((Product.BasicPrice + ValueAdd),0), 
                                              Discounted = ISNULL((Select (Product.BasicPrice + (ValueAdd -(ValueAdd *(Discount*0.01))))
                                                     From DealerDiscount 
                                                     Where CategoryId = Product.GrandCategoryId AND DealerId=@dealerid),0)
                                        From Product  Where 1=1 ';
    ....
    if (@GrandId > 0 and @ParentId>0 and @ChildId = 0 and @collectionId=0)
                    Begin
                        Set @sql  = @sql + ' AND Product.ParentCategoryId = @ParentId AND Product.GrandCategoryId = @GrandId '
                    End
    

    特别注意,我没有将当前参数值连接到生成的 SQL 中。

    然后你称它为:

    exec sp_executesql @sql, N'@dealerid int, @GrandId int',
                             @dealerid, @GrandId
                          -- ^^^ todo: add every parameter you need
    

    第一个参数是TSQL;第二个参数 (N'@dealerid int, @GrandId int') 是通过标准 SQL 语法描述参数的文字,然后我们映射要使用的值。在这种情况下,为方便起见,我们使用相同的名称 - 但这不是必需的。

    【讨论】:

      【解决方案2】:

      在构建查询时,您需要将变量附加为字符串,而不仅仅是分配。 请尝试:

      ALTER proc [dbo].[GetAllProductById] 
      (
          @collectionId int,
          @GrandId int  ,
          @ParentId int ,
          @ChildId int,
          @dealerid varchar(50) 
      )
      As
      Begin
      
      Declare @sql as varchar(max)
       -- In case dealer is logged in ,then calculate the Discounted amount and return the same,
          -- else return Mrp and Our Price for all other customers
      
          IF  @collectionid<=0
      
              BEGIN
                  IF @dealerid<>''
                      BEGIN
                          SET @sql = '    Select Top(5) Product.Id,ProdImage,ProductCode, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((Product.BasicPrice + ValueAdd),0), 
                                                Discounted = ISNULL((Select (Product.BasicPrice + (ValueAdd -(ValueAdd *(Discount*0.01))))
                                                       From DealerDiscount 
                                                       Where CategoryId = Product.GrandCategoryId AND DealerId='+@dealerid+'),0)
                                          From Product  Where 1=1 ';
                      END
                   ELSE
                      BEGIN
                          SET @sql = '    Select Top(5) Id,ProdImage,ProductCode, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((BasicPrice + ValueAdd),0), Discounted=0 
                                          From Product
                                          Where 1=1 ';
                      END 
      
              END
          ELSE
              BEGIN
                  IF @dealerid<>''
                      BEGIN
                          SET @sql = '    Select  Product.Id,ProdImage,ProductCode,Collections.Name,Collections.Id, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((Product.BasicPrice + ValueAdd),0), 
                                                Discounted = ISNULL((Select (Product.BasicPrice + (ValueAdd -(ValueAdd *(Discount*0.01))))
                                                       From DealerDiscount 
                                                       Where CategoryId = Product.GrandCategoryId AND DealerId='+@dealerid+'),0)
                                          FROM    Collections INNER JOIN
                                                  Product ON Collections.Id = Product.CollectionId 
                                                  where Product.CollectionId='+CAST(NVARCHAR(50), @collectionId)+'   AND 1=1 ';
                      END
                   ELSE
                      BEGIN
                          SET @sql = '    Select  Product.Id,ProdImage,Collections.Name,Collections.Id,ProductCode, ProductName,MrpPrice, BasicPrice,ValueAdd, Price =ISNULL((BasicPrice + ValueAdd),0), Discounted=0 
                                          FROM    Collections INNER JOIN
                                                  Product ON Collections.Id = Product.CollectionId 
                                                  where Product.CollectionId='+CAST(NVARCHAR(50), @collectionId)+' AND 1=1 ';
                      END 
      
                  if (@GrandId > 0 and @ParentId>0 and @ChildId > 0 and @collectionId=0)
                      Begin
                          Set @sql  = @sql + ' Product.ParentCategoryId = '+ Convert(Varchar, @ParentId)+' AND Product.GrandCategoryId = '+ Convert(Varchar, @GrandId)+' AND Product.ChitdCategoryId = '+Convert(varchar,@ChildId);
                      End
                  if (@GrandId > 0 and @ParentId>0 and @ChildId = 0 and @collectionId=0)
                      Begin
                          Set @sql  = @sql + ' Product.ParentCategoryId = '+ Convert(Varchar, @ParentId)+' AND Product.GrandCategoryId = '+ Convert(Varchar, @GrandId)
                      End
                  if (@GrandId > 0 and @ParentId=0 and @ChildId = 0 and @collectionId=0)
                      Begin
                          Set @sql  = @sql + ' AND Product.GrandCategoryId = '+ Convert(Varchar, @GrandId)
                      End
              END
      
              exec(@sql)
      
      END   
      

      【讨论】:

      • IMO,连接输入从不是这样做的好方法,并且可能(至少对于[n][var]char)导致 SQL 注入错误。 sp_executesql 将是一种更值得称道的方法。
      • 感谢@MarcGravell 的宝贵提示。 Stack Overflow 是学习新事物的好地方!
      猜你喜欢
      • 1970-01-01
      • 2018-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多