Sql Server 存儲過程分頁
- 2019 年 10 月 4 日
- 筆記
在企業級項目開發中,分頁查詢,獲取某一類數據的List列表,這一功能是最普遍也是最重要的功能。其做法有很多種,例如ORM中自定義分頁查詢,一般情況下是拼接強類型的查詢條件,然後轉換成sql語句,查出出分頁結果。在ORM轉換過程中會稍微損失性能,效率會降低。對於百萬級以上的大數據量,要求查詢介面顯示速度快,此時手動寫存儲過程,並且在存儲過程中分頁是最佳選擇。下面給出具體的示例與說明:
============================================= -- Author: XXX -- Create date: XXX -- Description: XXX -- ============================================= ALTER PROCEDURE [dbo].[SP_GetRptNoCooperation] @custId NVARCHAR(30) --客戶編號 ,@custNam NVARCHAR(100) --客戶名稱 ,@stopWorkingDateStart DATETIME -- 停止合作日期_起 ,@stopWorkingDateEnd DATETIME -- 停止合作日期_止 ,@crtDtStart DATETIME -- 申報日期_起 ,@crtDtEnd DATETIME -- 申報日期_止 ,@pageSize INT --單頁記錄條數 ,@pageIndex INT --當前頁左索引 ,@totalRowCount INT OUTPUT --輸出總記錄條數 AS BEGIN DECLARE @RowStart INT; --定義分頁起始位置 DECLARE @RowEnd INT; --定義分頁結束位置 DECLARE @Sql NVARCHAR(MAX); --拼接SQL語句 DECLARE @SqlSelectResult NVARCHAR(MAX); --Sql查詢結果語句 -- DECLARE @SqlCount NVARCHAR(MAX); --Sql Count計數語句 IF @pageIndex > 0 BEGIN SET @pageIndex = @pageIndex -1; SET @RowStart = @pageSize * @pageIndex + 1; SET @RowEnd = @RowStart + @pageSize - 1; END ELSE BEGIN SET @RowStart = 1; SET @RowEnd = 999999; END IF ISNULL(@pageSize, 0) <> 0 AND @pageSize <> 0 BEGIN SET @sql = 'With CTE_RptNoCooperation as ( SELECT ROW_NUMBER () OVER (ORDER BY rnc.CrtDt DESC) AS RowNumber ,rnc.Id ,rnc.CustId --客戶編號 ,rnc.StopWorkingDate --停止合作日期(最後一次發貨日期) ,rnc.Arrears --截止申報日期的總欠 ,rnc.CheckAccount --對賬情況(是否對清、對至幾月份) ,rnc.Communication --前期溝通處理情況(是否有退貨/業務溝通催款情況/報法務室/出律師函或公函等) ,rnc.MaySituation --XXXX年X月跟蹤情況 ,rnc.JuneManagerSuggest --XXXX年X月部區經理意見 ,rnc.JunefinancialOpinion --財務審計部意見 ,rnc.CEOInstruct --總裁批示 ,rnc.CrtDt --創建日期 ,rnc.CrtBy --創建人id ,rnc.UpdateDt --修改日期 ,rnc.UpdateBy --修改人id ,ci.CustNam --客戶名稱 ,ai2.AreaNam --區域名稱,省份 FROM RptNoCooperation AS rnc LEFT JOIN CustInfo AS ci ON rnc.CustId = ci.CustId LEFT JOIN AreaInfo AS ai ON ci.AreaCode = ai.AreaCode INNER JOIN AreaInfo AS ai2 ON ai.PareaCode = ai2.AreaCode WHERE 1 = 1 ';--此處CTE表達式右括弧不寫,在後面根據條件判斷,追加 END ELSE BEGIN SET @sql = 'SELECT rnc.Id ,rnc.CustId --客戶編號 ,rnc.StopWorkingDate --停止合作日期(最後一次發貨日期) ,rnc.Arrears --截止申報日期的總欠 ,rnc.CheckAccount --對賬情況(是否對清、對至幾月份) ,rnc.Communication --前期溝通處理情況(是否有退貨/業務溝通催款情況/報法務室/出律師函或公函等) ,rnc.MaySituation --XXXX年X月跟蹤情況 ,rnc.JuneManagerSuggest --XXXX年X月部區經理意見 ,rnc.JunefinancialOpinion --財務審計部意見 ,rnc.CEOInstruct --總裁批示 ,rnc.CrtDt --創建日期 ,rnc.CrtBy --創建人id ,rnc.UpdateDt --修改日期 ,rnc.UpdateBy --修改人id ,ci.CustNam --客戶名稱 ,ai2.AreaNam --區域名稱,省份 FROM RptNoCooperation AS rnc LEFT JOIN CustInfo AS ci ON rnc.CustId = ci.CustId LEFT JOIN AreaInfo AS ai ON ci.AreaCode = ai.AreaCode INNER JOIN AreaInfo AS ai2 ON ai.PareaCode = ai2.AreaCode WHERE 1 = 1 '; END IF ISNULL(@custId,'') <> '' BEGIN --根據客戶id查詢 SET @Sql = @Sql + ' AND rnc.CustId = ''' + @custId + ''''; END IF ISNULL(@custNam,'') <> '' BEGIN --根據客戶名稱 模糊查詢 SET @Sql = @Sql + ' AND ci.CustNam like ''%' + @custNam + '%'''; END IF ISNULL(@stopWorkingDateStart,'') <> '' BEGIN --停止合作日期_起 SET @stopWorkingDateStart = @stopWorkingDateStart + ' 00:00:00.000'; SET @Sql = @Sql + ' AND rnc.StopWorkingDate >= ''' + @stopWorkingDateStart + ''''; END IF ISNULL(@stopWorkingDateEnd,'') <> '' BEGIN --停止合作日期_止 SET @stopWorkingDateEnd = @stopWorkingDateEnd + ' 23:59:59.999' SET @Sql = @Sql + ' AND rnc.StopWorkingDate <= ''' + @stopWorkingDateEnd + ''''; END IF ISNULL(@crtDtStart,'') <> '' BEGIN --申請日期_起 SET @crtDtStart = @crtDtStart + ' 00:00:00.000'; SET @Sql = @Sql + ' AND rnc.CrtDt >= ''' + @crtDtStart + ''''; END IF ISNULL(@crtDtEnd,'') <> '' BEGIN --申請日期_止 SET @crtDtEnd = @crtDtEnd + ' 23:59:59.999' SET @Sql = @Sql + ' AND rnc.CrtDt <= ''' + @crtDtEnd + ''''; END IF ISNULL(@pageSize, 0) <> 0 AND @pageSize <> 0 BEGIN SET @Sql = @Sql + ') '; SET @SqlCount = @Sql + ' SELECT @Temp = COUNT(*) FROM CTE_RptNoCooperation;'; SET @SqlSelectResult = @Sql + ' SELECT * FROM CTE_RptNoCooperation WHERE RowNumber Between ' + Convert(varchar(10),@RowStart) + ' And ' + Convert(varchar(10),@RowEnd) + ';'; --Print (@SqlSelectResult); --EXEC (@SqlSelectResult); EXEC sp_executesql @SqlSelectResult; EXEC sp_executesql @SqlCount,N'@Temp int output',@totalRowCount output ; END ELSE BEGIN SET @Sql = @sql + ' order by rnc.CrtDt DESC '; SET @totalRowCount = 0; --Print (@Sql); EXEC (@Sql); END END GO
SQL Server 2012 及以上版本使用OFFSET/FETCH NEXT實現分頁查詢效率更高 ,