【问题标题】:SQL query behaving differently when run with sp_executesql使用 sp_executesql 运行时 SQL 查询的行为不同
【发布时间】:2015-12-29 21:27:14
【问题描述】:

我在 SQL Server 2012 中有一个查询,我首先在不使用 sp_executesql 的情况下运行,然后使用 sp_executesql 运行它。奇怪的是,这两次运行都给出了不同的结果,而它们应该是相同的,因为它们使用的是相同的 SQL 查询。

我什至尝试将OUTPUT 用于@productId,如下面的代码所示,但即便如此,它也没有任何区别。在本文末尾给出的屏幕截图中,前两个结果集应该与后两个结果集重复,但它们不会。

EXECUTE sp_executesql   @qry,
                        N'@maxRows int,@startingRowNumber int,@productId bigint OUTPUT',
                        @maxRows = @maxRows,
                        @productId = @productId OUTPUT,
                        @startingRowNumber = @numberOfRowsToSkip

问题:是什么导致同一查询的结果不同?

DECLARE @startingRowNumber INT = 1;
DECLARE @productId BIGINT;
DECLARE @maxRows INT = 10;
DECLARE @qryCount NVARCHAR(MAX);
DECLARE @qry NVARCHAR(MAX);
DECLARE @numberOfRowsToSkip INT;
SET @numberOfRowsToSkip = @startingRowNumber - 1;

--RUN query batch without sp_executesql
SELECT  @productId = MAX(ProductId)
             FROM (SELECT TOP (@startingRowNumber)
                    ProductId
                    FROM dbo.Prods
                    WHERE [Product Cost] < 1005
                    ORDER BY ProductId ASC) x;
SELECT @productId AS ProductId;
SELECT ProductId,Product,Vendor,VendorId,[Product Cost]
FROM dbo.Prods WITH (NOLOCK)
WHERE ProductId >= @productId
AND [Product Cost] < 1005
ORDER BY [Product Cost] ASC OFFSET @numberOfRowsToSkip
ROWS FETCH NEXT @maxRows ROWS ONLY;

--RUN query batch using sp_executesql
SET @qry = N'SELECT @productId = MAX(ProductId)
             FROM (SELECT TOP (@startingRowNumber)
                    ProductId
                    FROM dbo.Prods
                    WHERE [Product Cost] < 1005
                    ORDER BY ProductId ASC) x;
SELECT @productId AS ProductId;
SELECT ProductId,Product,Vendor,VendorId,[Product Cost]
FROM dbo.Prods WITH (NOLOCK)
WHERE ProductId >= @productId
AND [Product Cost] < 1005
ORDER BY [Product Cost] ASC OFFSET @numberOfRowsToSkip
ROWS FETCH NEXT @maxRows ROWS ONLY';

EXECUTE sp_executesql   @qry,
                        N'@maxRows int,@startingRowNumber int,@productId bigint',
                        @maxRows = @maxRows,
                        @productId = @productId,
                        @startingRowNumber = @numberOfRowsToSkip
PRINT N'Executed select query'

查询结果截图

更新 1

我还注意到一个有趣的事情是查询 1 返回一个值,但查询 2 没有。我很确定这个问题的答案将是原始问题的答案。

查询 1

SELECT @productId = Max(x.ProductId) FROM
(SELECT TOP (@startingRowNumber)  ProductId FROM dbo.Prods WHERE
      [Product Cost] < 1005 ORDER BY ProductId ASC) x;
SELECT @productId AS ProductId

查询 2

SET @qry = N'SELECT @productId = Max(x.ProductId) FROM
(SELECT TOP (@startingRowNumber)  ProductId FROM dbo.Prods WHERE
      [Product Cost] < 1005 ORDER BY ProductId ASC) x;';
EXECUTE sp_executesql   @qry,
                        N'@maxRows int,@startingRowNumber int,@productId bigint OUTPUT',
                        @productId = @productId OUTPUT,
                        @startingRowNumber = @numberOfRowsToSkip,
                        @maxRows = @maxRows
SELECT @productId AS ProductId

【问题讨论】:

    标签: sql-server-2012 sp-executesql


    【解决方案1】:

    我认为您的差异是由以下原因引起的:

    No dynamic: {OFFSET @startingRowNumber} 
    Dynamic: {OFFSET @numberOfRowsToSkip} = {OFFSET @startingRowNumber - 1;}
    

    此外,@productId 在您的动态查询中分配,但也作为输入提供。您应该在查询中声明它并将其从sp_executesql 的参数列表中删除:

    DECLARE @productId BIGINT
    SET @qry = N'SELECT @productId = MAX(ProductId)
                 FROM (SELECT TOP (@startingRowNumber)
    ...
    

    【讨论】:

    • 感谢您指出这一点。即使这样也不能解决问题。我将编辑我的查询。
    • 似乎由于某种原因@productId 在使用 sp_executesql 执行时没有被设置,但在普通 SQL 查询中它被设置了。我很确定这也是整个查询不起作用的原因。
    • 我刚刚添加了 UPDATE 1。
    • 尝试从输入参数中删除@productId,因为您在查询中分配它。
    • 当我尝试使用您的建议时,我收到一条错误消息:Must declare the scalar variable "@productId"。 @productId 稍后在 where 子句中的查询中使用,因此出现此错误。
    【解决方案2】:

    我的动态查询中有一个愚蠢的错误。以下 sp_executesql 导致正确执行。我不得不改变两件事。另外,我不必将@productId 声明为OUTPUT 类型参数。

    • @startingRowNumber = @numberOfRowsToSkip 更改为@startingRowNumber = @startingRowNumber
    • 在 sp_executesql 中添加了 @numberOfRowsToSkip 的另一个参数

    使其工作的代码

    EXECUTE sp_executesql   @qry,
                        N'@maxRows int,@startingRowNumber int,@productId bigint,@numberOfRowsToSkip int ',
                        @maxRows = @maxRows,
                        @productId = @productId,
                        @startingRowNumber = @startingRowNumber,
                        @numberOfRowsToSkip = @numberOfRowsToSkip
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多