2017-09-15 91 views
4

我們當前正在使用SQL server 2016.基於微軟頁面Deprecated Database Engine Features in SQL Server 2016SET ROWCOUNT已被棄用。所以我們試圖將所有SET ROWCOUNT N報表轉換爲TOP(N)報表。看起來很容易,但我們遇到了一個情況,其中N是存儲過程中的一個參數,默認爲0.當n可能爲0時,將SET ROWCOUNT n轉換爲TOP(n)

因此在舊代碼中,它類似於SET ROWCOUNT @NumRows。如果@NumRows爲0,則表示關閉SET ROWCOUNT選項,因此以下查詢將返回所有行。但是如果我們將其轉換爲TOP(@NumRows),那意味着它將返回0行。爲了避免這個問題,我們可以添加額外的IF條件,如果@NumRows爲0,則將@NumRows設置爲一個很大的數字。或者我們可以添加額外的IF條件,如果@NumRows爲0,那麼我們使用SELECT沒有TOP,否則我們像往常一樣做SELECT TOP(N)

但是這些解決方案中的任何一個都會在存儲過程中添加額外的代碼,所以我的問題是:考慮到N可能爲0,是否有一種將SET ROWCOUNT N轉換爲TOP (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 
+0

優雅?但是,在插入到你的'top'子句之前,你可以說'選擇@NumRows = iif(@NumRows = 0,2147483648,@NumRows)'。這就是說,這可能會給你很糟糕的查詢計劃。除非您有數千個程序需要查找/替換,否則您可能需要考慮指定兩個不同代碼路徑的額外工作。你的旅費可能會改變。 – Xedni

+0

我會警告不要使用多個執行路徑。它可能會導致非常有趣的性能問題。 Gail Shaw在這裏有一個很棒的博客文章。 http://www.sqlinthewild.co.za/index.php/2009/09/15/multiple-execution-paths/ –

+0

@SeanLange感謝您的鏈接。我通讀了它並理解不同執行計劃的可能性。所以如果我不使用不同的執行路徑,那意味着我總是使用'TOP(N)'。然後我需要檢查N值是否爲0。如果它是0,我可以從表中'NumRows' = 2147483647或'NumRows' = count(*),這對查詢計劃有什麼影響? – Dongminator

回答

1

這聽起來像你的程序定義是這樣的。如果您發佈了定義,那麼在這裏可以更容易地獲得幫助。

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時,您需要指定一個順序或您無法知道將返回哪些行。

- EDIT--

謝謝你的代碼示例。看來我在這裏的猜測非常接近。您不必在此處使用IF語句,您可以直接在查詢中更輕鬆地完成此操作。這與lad2025發佈的答案類似。

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

感謝您將默認設置爲2147483648的建議。我還編輯了我的原始問題,以包括存儲過程的外觀。我認爲如果當前默認值爲0,我們可以將其更改爲2147483648.但是,如果默認值不是0,那麼我們應該這樣做:'if @NumRows = 0,set @NumRows = 2147483648'?或者只是在所有默認情況下使用這個IF語句? – Dongminator

+0

查看我的編輯,比在這裏使用IF語句更簡單。 –

1

你可以使用子查詢/表達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; 

Rextester Demo

注意的可能性能影響。另外TOP沒有明確的ORDER BY可能會返回不同的結果集。

+0

感謝您的回答!你能否詳細說明可能的性能影響?如果您可以分享幾個鏈接,我也可以閱讀這些鏈接。 – Dongminator