SqlServer存儲過程應用二:分頁查詢數據並動態拼接where條件


前言

開發中查詢功能是貫穿全文的,我們來盤一盤使用存儲過程分頁查詢,並且支持動態拼接where條件。

划重點:支持動態拼接where條件

對存儲過程的使用有疑問的同學去【SqlServer存儲過程的創建與使用】補補課。

至於大家是使用自定義sql查詢還是相關ORM框架查詢就不討論了,我們就簡單介紹存儲過程的查詢(自定義sql查詢)。

 


 

創建存儲過程並執行

流程圖如下,我們根據流程圖進行代碼實現。

 


1、創建帶參的存儲過程

 

創建帶參數的存儲過程首先要在存儲過程中聲明該參數,每個存儲過程參數都必須用惟一的名稱進行定義。

與標准的Transact-SQL變量相同,參數名必須以@為前綴,並且遵從對象標識符規則。

當用戶不提供該參數的值時可以使用一個默認值來代替。

在執行帶參數的存儲過程時,既可以通過顯式指定參數名稱並賦予適當的值,也可以通過提供在CREATE PROCEDURE語句中給定的參數值(不指定參數名稱)來向存儲過程傳遞值。

在存儲過程PRO_Student_IN中命名4個參數,其定義順序為@Chinese、@English、@maths和@class。

例如,將值傳遞給存儲過程指定的參數名稱。

EXEC PRO_Student_IN @class="三年一班",@Chinese=85,@maths=85,@English=85

例如,按照參數的位置傳遞,而不命名參數名稱。

EXEC PRO_Student_IN 85,85,85,"三年一班"

 

2、定義一個參數,用於接受拼接后的sql語句

通過指定過程參數,調用程序可以將值傳遞給過程的主體。

如果將參數標記為 OUTPUT 參數,則過程參數還可以將值返回給調用程序。

一個過程最多可以有 2100 個參數,每個參數都有名稱、數據類型和方向。 還可以為參數指定默認值(可選)。

使用過程調用提供的參數值必須為常量或變量,不能將函數名稱作為參數值。 變量可以是用戶定義的變量或系統變量(如 @@spid)。

  1. 需要指定參數名稱;
  2. 指定參數數據類型;
  3. 可以指定參數默認值;
  4. 可以指定參數方式(默認為輸入參數)。

 

3、創建一個臨時表,用於存儲查詢拼接條件后的結果集

臨時表與永久表相似,但臨時表存儲在tempdb中,當不再使用時會自動刪除。臨時表有兩種類型:本地和全局。它們在名稱、可見性以及可用性上有區別。

對於臨時表有如下幾個特點:

  • 本地臨時表就是用戶在創建表的時候添加了“#”前綴的表,其特點是根據數據庫連接獨立。只有創建本地臨時表的數據庫連接有表的訪問權限,其它連接不能訪問該表;
  • 不同的數據庫連接中,創建的本地臨時表雖然“名字”相同,但是這些表之間相互並不存在任何關系;
  • 在SQLSERVER中,通過特別的命名機制保證本地臨時表在數據庫連接上的獨立性。

真正的臨時表利用了數據庫臨時表空間,由數據庫系統自動進行維護,因此節省了表空間。並且由於臨時表空間一般利用虛擬內存,大大減少了硬盤的I/O次數,因此也提高了系統效率。

臨時表在事務完畢或會話完畢數據自動清空,不必記得用完后刪除數據。

本地臨時表

  • 本地臨時表的名稱以單個數字符號 (#) 打頭;
  • 它們僅對當前的用戶連接(也就是創建本地臨時表的connection)是可見的;
  • 當用戶從 SQL Server 實例斷開連接時被刪除。

4、分頁查詢返回最終的sql語句和總行數,查詢條件加上臨時表的數據,最后刪除臨時表

Sqlserver數據庫分頁查詢一直是Sqlserver的短板,分頁方式也有好幾種,假設有表ARTICLE,字段ID、YEAR...(其他省略),

數據53210條(客戶真實數據,量不大),分頁查詢每頁30條,查詢第1500頁(即第45001-45030條數據),字段ID聚集索引,YEAR無索引。


第一種方案、最簡單、普通的方法:

SELECT TOP 30 * FROM ARTICLE WHERE ID NOT IN(SELECT TOP 45000 ID FROM ARTICLE ORDER BY YEAR DESC, ID DESC) ORDER BY YEAR DESC,ID DESC

平均查詢100次所需時間:45s

 

第二種方案:

SELECT * FROM (  SELECT TOP 30 * FROM (SELECT TOP 45030 * FROM ARTICLE ORDER BY YEAR DESC, ID DESC) f ORDER BY f.YEAR ASC, f.ID DESC) s ORDER BY s.YEAR DESC,s.ID DESC 

平均查詢100次所需時間:138S

 

第三種方案:

SELECT * FROM ARTICLE w1, 
(
    SELECT TOP 30 ID FROM 
    (
        SELECT TOP 50030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
    ) w ORDER BY w.YEAR ASC, w.ID ASC
) w2 WHERE w1.ID = w2.ID ORDER BY w1.YEAR DESC, w1.ID DESC

平均查詢100次所需時間:21S

 

第四種方案:

SELECT * FROM ARTICLE w1 
    WHERE ID in 
        (
            SELECT top 30 ID FROM 
            (
                SELECT top 45030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
            ) w ORDER BY w.YEAR ASC, w.ID ASC
        ) 
    ORDER BY w1.YEAR DESC, w1.ID DESC

平均查詢100次所需時間:20S

 

第五種方案:

SELECT w2.n, w1.* FROM ARTICLE w1, (  SELECT TOP 50030 row_number() OVER (ORDER BY YEAR DESC, ID DESC) n, ID FROM ARTICLE ) w2 WHERE w1.ID = w2.ID AND w2.n > 50000 ORDER BY w2.n ASC 

平均查詢100次所需時間:15S


完整存儲過程代碼

/**author:熊澤        date:2021-04-16    project:SqlServer存儲過程應用二:分頁查詢數據並動態拼接where條件*/
--創建一個查詢學生的存儲過程
CREATE PROCEDURE ProcedureStudent
    @pageIndex INT ,        --當前頁(如1:第1頁)
    @pageCount INT,            --每頁條數(如50:每頁50條)
    @rowTotal INT OUTPUT ,    --返回的總行數 
    @strWhere VARCHAR(5000) --程序動態拼接的sql查詢條件
AS
BEGIN
    /**begin創建拼接動態條件 */
    DECLARE @sq_temp AS VARCHAR(2000)  --定義拼接后的sql語句
    CREATE TABLE #temp (  --創建一個拼接查詢條件查詢出來的結果用於做子查詢
        Number VARCHAR(50)
    )

    SET @sq_temp ='SELECT Number FROM a_Students where 1 = 1 '
                + CASE WHEN ISNULL(@strWhere,'') = '' THEN '' ELSE @strWhere END --動態拼接的條件

    --將拼接的條件寫入臨時表
    INSERT INTO #temp (Number) EXEC (@sq_temp);

    /**end創建拼接動態條件 */


     --分頁查詢語句sql
     SELECT * FROM (SELECT  
                        row_number()over (order by a.Number desc)Id,
                        a.Number 學號 ,
                        a.Name 姓名 ,
                        b.ClassName 班級 ,
                        c.Java ,
                        c.Python ,
                        c.C# ,
                        c.SqlDB
                FROM    a_Students a
                        LEFT JOIN a_StudentClass b ON a.ClassId = b.ClassId
                        LEFT JOIN a_StudentsScore c ON a.Number = c.Number
                        WHERE  a.Number IN (SELECT  Number FROM #temp)
                       )temp 
       WHERE temp.Id between (@pageIndex-1)*@pageCount+1 and @pageIndex*@pageCount;

       --返回總條數
       SELECT  @rowTotal=COUNT(*)  FROM dbo.a_Students WHERE Number IN (SELECT  Number FROM #temp)

       DROP TABLE #temp  --刪除臨時表
END
GO

調用存儲過程

1、沒有動態拼接where條件

--調用分頁存儲過程,沒有where條件
DECLARE @total INT 
EXEC ProcedureStudent 1,5,@total OUT,''
SELECT @total 返回的總行數

2、有動態拼接where條件

--調用分頁存儲過程,有where條件:學號為100014的數據
DECLARE @total INT 
EXEC ProcedureStudent 1,5,@total OUT,' and Number=''100014'''  --動態拼接條件:學號為100014的數據
SELECT @total 返回的總行數

 


 

我們就介紹到這里吧,拜拜。

 

歡迎關注訂閱微信公眾號【熊澤有話說】,更多好玩易學知識等你來取
作者:熊澤-學習中的苦與樂
公眾號:熊澤有話說
出處: https://www.cnblogs.com/xiongze520/p/14667408.html
創作不易,任何人或團體、機構全部轉載或者部分轉載、摘錄,請在文章明顯位置注明作者和原文鏈接。  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM