Sql server 2012 使用sp_executesql运行时SQL查询的行为不同

Sql server 2012 使用sp_executesql运行时SQL查询的行为不同,sql-server-2012,sp-executesql,Sql Server 2012,Sp Executesql,我在SQL Server 2012中有一个查询,我首先不使用sp_executesql运行该查询,然后使用sp_executesql运行该查询。奇怪的是,这两个运行都会给出不同的结果,而它们应该是相同的,因为它们使用的是相同的SQL查询 我甚至尝试过在下面的代码中使用@productId的输出,但即使这样也没有什么不同。在本文末尾给出的屏幕截图中,前两个结果集应该对后两个结果集重复,但它们不会 EXECUTE sp_executesql @qry,

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

我甚至尝试过在下面的代码中使用@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

我认为你的差异是由以下原因造成的:

No dynamic: {OFFSET @startingRowNumber} 
Dynamic: {OFFSET @numberOfRowsToSkip} = {OFFSET @startingRowNumber - 1;}
另外,@productId在动态查询中分配,但也作为输入提供。您应该在查询中声明它,并将其从sp_executesql的参数列表中删除:


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

将@startingRowNumber=@numberOfRowsToSkip更改为@startingRowNumber=@startingRowNumber 在sp_executesql中添加了另一个参数@numberOfRowsToSkip 使它工作的代码


谢谢你指出这一点。即使这样也不能解决问题。我将编辑我的查询。似乎出于某种原因,在使用sp_executesql执行时@productId没有被设置,但在使用普通SQL查询时,它被设置了。我很确定这也是整个查询不起作用的原因。我刚刚添加了更新1。尝试从输入参数中删除@productId,因为您在查询中分配了它。当我尝试使用您的建议时,我收到一个错误,说必须声明标量变量@productId@productId稍后用于where子句中的查询,因此出现此错误。
DECLARE @productId BIGINT
SET @qry = N'SELECT @productId = MAX(ProductId)
             FROM (SELECT TOP (@startingRowNumber)
...
EXECUTE sp_executesql   @qry,
                    N'@maxRows int,@startingRowNumber int,@productId bigint,@numberOfRowsToSkip int ',
                    @maxRows = @maxRows,
                    @productId = @productId,
                    @startingRowNumber = @startingRowNumber,
                    @numberOfRowsToSkip = @numberOfRowsToSkip