Sql server 当n可以为0时,转换将行数n设置为TOP(n)

Sql server 当n可以为0时,转换将行数n设置为TOP(n),sql-server,tsql,sql-server-2016,sql-limit,Sql Server,Tsql,Sql Server 2016,Sql Limit,我们目前正在使用SQL server 2016。根据Microsoft页面,设置行数已被弃用。因此,我们试图将所有SET ROWCOUNT N语句转换为TOP(N)语句。这看起来很简单,但我们遇到了一个例子,其中N是存储过程中的一个参数,默认为0 因此,在旧代码中,它类似于SET ROWCOUNT@NumRows。如果@NumRows为0,则意味着关闭设置行数选项,因此以下查询将返回所有行。但如果我们将其转换为TOP(@NumRows),这意味着它将返回0行。为了避免这个问题,我们可以添加额外的

我们目前正在使用SQL server 2016。根据Microsoft页面,
设置行数
已被弃用。因此,我们试图将所有
SET ROWCOUNT N
语句转换为
TOP(N)
语句。这看起来很简单,但我们遇到了一个例子,其中N是存储过程中的一个参数,默认为0

因此,在旧代码中,它类似于
SET ROWCOUNT@NumRows
。如果
@NumRows
为0,则意味着关闭
设置行数
选项,因此以下查询将返回所有行。但如果我们将其转换为
TOP(@NumRows)
,这意味着它将返回0行。为了避免这个问题,我们可以添加额外的IF条件,如果
@NumRows
为0,则将
@NumRows
设置为一个巨大的数字。或者我们可以添加额外的IF条件,如果
@NumRows
为0,那么我们使用不带TOP的SELECT,否则我们会像往常一样
选择TOP(N)

但是这两种解决方案中的任何一种都会在存储过程中添加额外的代码,因此我的问题是:考虑到N可以是0,是否有一种优雅的方法将
设置行数N
转换为
顶部(N)

更新:添加了存储过程模板

-- Default to 0, in this case, SET ROWCOUNT 0 will return all result
-- But if we change it to TOP(@rows), it returns no result.
CREATE PROCEDURE Proc1  
  @rows int = 0  
AS  
SET ROWCOUNT @rows
SELECT Col1 FROM table1
ORDER BY Col2
SET ROWCOUNT 0

-- In this case, the default is not 0
-- But the program that calls this stored procedure could pass in value 0. 
-- We also don't want to change default value for this stored procedure. 
-- So I think in this case, we may have to add IF @rows = 0, SET @rows = huge_number
CREATE PROCEDURE Proc2
  @rows int = 10
AS
SET ROWCOUNT @rows
SELECT Col3 FROM table2
ORDER BY Col4
SET ROWCOUNT 0

您可以在
TOP
子句中使用子查询/表达式,而不是使用特定值:

DECLARE @param INT = 0;

SELECT TOP (SELECT IIF(@param=0,2000000, @param)) * FROM sys.objects;
SELECT TOP (IIF(@param=0,2000000, @param)) * FROM sys.objects;


注意可能的性能影响。另外,
TOP
没有明确的
orderby
可能会返回不同的结果集。

听起来您的过程定义是这样的。如果您发布了定义,那么在这里提供帮助会容易得多

create procedure MyProc
(
    @NumRows int = 0
)
as 
    if @NumRows > 0
        set rowcount @NumRows
    else
        set rowcount 0

    select Columns
    from Table
假设定义如上所述,您可以将其更改为类似这样的内容

create procedure MyProc
(
    @NumRows int = 2147483648 --max value for an int. This could be a bigint also if you have LOTS of data.
)
as 
    select top(@NumRows) Columns
    from Table
请注意,使用TOP时,您需要指定order by,否则无法知道将返回哪些行

--编辑--

谢谢你的代码示例。看来我的猜测很接近。您不必在这里使用IF语句,您可以直接在查询中轻松地完成这一点。这与LAD2055发布的答案类似

select top(isnull(nullif(@NumRows, 0), 2147483647)) Columns
from Table

优雅的不可以。但是在插入到
top
子句之前,您可以说
select@NumRows=iif(@NumRows=02147483648,@NumRows)
。也就是说,这很可能会给您带来糟糕的查询计划。除非您有数千个过程需要查找/替换,否则您可能需要考虑指定两个不同的代码路径的额外努力。您的里程数可能会有所不同。我要提醒您不要使用多个执行路径。这会导致非常有趣的性能问题。盖尔·肖在这里有一篇关于这个话题的博文@谢谢你的链接。我通读了一遍,理解了不同执行计划的可能性。因此,如果我不使用不同的执行路径,这意味着我将始终使用
TOP(N)
。然后我需要检查N值,看看它是否为0。如果它是0,我可以从表中生成
NumRows
=2147483647或
NumRows
=count(*),这会对查询计划产生什么影响?
SET ROWCOUNT
不反对
SELECT
语句,仅用于INSERT、UPDATE和delete感谢您的回答!您能否详细说明可能的性能影响?如果你可以分享一些链接,我也可以阅读。谢谢你建议将默认设置为2147483648。我还编辑了我的原始问题,以包括存储过程的外观。我认为如果当前默认值为0,我们可以将其更改为2147483648。但是如果默认值当前不是0,那么我们是否应该这样做,
如果@NumRows=0,设置@NumRows=2147483648
?或者只是在所有默认情况下使用此IF语句?请参阅我的编辑,以了解比在此处使用IF语句更简单的方法。