發(fā)文章
發(fā)文工具
撰寫
網(wǎng)文摘手
文檔
視頻
思維導(dǎo)圖
隨筆
相冊
原創(chuàng)同步助手
其他工具
圖片轉(zhuǎn)文字
文件清理
AI助手
留言交流
其實很多非業(yè)務(wù)邏輯的功能,比如分頁,數(shù)據(jù)過濾,可以在程序上面節(jié)省很多內(nèi)存和CPU時間,但往往又找不到一個比較通用有效的方法,花了點時間,終于把我想要的在數(shù)據(jù)庫中分頁和過濾的功能寫了出來,在這里分享。
第一期望:我希望輸入頁碼(pageIndex),每頁顯示的記錄數(shù)(pageSize),然后這個存儲過程就可以給我一個當(dāng)前頁的數(shù)據(jù)集。
首先,我假設(shè)有個表叫Configuration,里面就3個字段,Id, Key, Value,就是一個簡單的數(shù)據(jù)表,定義如下:
CREATE TABLE [dbo].[Configuration] ( [Id] int NOT NULL IDENTITY (1,1), [Key] varchar(20) NOT NULL UNIQUE, [Value] nvarchar(max) NULL )
再者,一個良好的代碼書寫規(guī)范是非常必要的,該注釋的地方千萬別省,在多數(shù)情況下,代碼的可讀性是非常重要的,除非因性能因素做必須得讓步。
/* PROCEDURE: [dbo].[sp_r_p_configuration] OPERATION: READ FEATURES: Paginate PURPOSE: provide a paginated list from the configuration table CREATOR: Jerry Weng CREATETIME: 2014-4-9 UPDATETIME: 2014-4-9 VERSION: 1.0 */ CREATE PROCEDURE [dbo].[sp_r_p_configuration] @pageIndex int = 1, /*which page of the total page*/ @pageSize int=10, /*how many records show in one page*/ @recordCount int OUTPUT, /*output: return the count of the total records in all pages*/ @pageCount int OUTPUT /*output: return the count of the total pages*/ AS declare @startRow int; -- the row number of the first record in the page declare @endRow int; -- the row number of the last record in the page set @startRow = (@pageIndex - 1) * @pageSize + 1; set @endRow= @startRow + @pageSize - 1; ;with tmp as (select (ROW_NUMBER() over(order by Id)) as row_id, [Id], [Key], [Value] from dbo.Configuration) select [Id], [Key], [Value] from tmp where row_id between @startRow and @endRow -- calculate the record count in all pages select @recordCount=COUNT(*) from dbo.Configuration -- calculate the page count set @pageCount = CEILING(@recordCount/CAST(@pageSize as float)) RETURN 0
這里用的ROW_NUMBER()來實現(xiàn)分頁,性能必拼SQL的方法好,WITH...AS可以省下一個表變量。最后計算總記錄數(shù)和頁數(shù)很簡單,算下就好了。
第二期望:這樣的,似乎差不多了,但是我還希望能夠有一套規(guī)則,來過濾結(jié)果集,并且還要有類似AND和OR的運算功能,而且我仍舊不希望用inline-script去實現(xiàn),能不用盡量不要用。
為了實現(xiàn)這個期望,我需要先定義怎么傳入過濾規(guī)則,我最終決定用的是xml數(shù)據(jù)類型而不是普通字符串,因為普通字符串有長度限制(如果你說可以用text,那我只能說太奢侈,小弟用不起),定短了可能被截斷出現(xiàn)錯誤輸出,定長了,最多也就8000個字符,也浪費,我不喜歡不確定因素,然而xml不一樣,既是結(jié)構(gòu)化數(shù)據(jù),又有索引支持,可長可短,客戶端也可直接序列化成字符串傳入,非常方便。于是剩下的是,約定一個規(guī)則,確定過濾規(guī)則的數(shù)據(jù)結(jié)構(gòu),在這里我專門寫了一個function來將xml轉(zhuǎn)換成table已被后用。P.S. 如果想傳一個數(shù)組到存儲過程,也可以用xml類型,比字符串加分隔符更安全。
/* FUNCTION: [dbo].[fun_xmlfilter_parse] OPERATION: READ FEATURES: PURPOSE: parse a table from a xml with the specific column name CREATOR: Jerry Weng CREATETIME: 2014-4-9 UPDATETIME: 2014-4-9 VERSION: 1.0 */ CREATE FUNCTION [dbo].[fun_xmlfilter_parse] ( @filter xml, /* The format should be: <filter> <rule column="COLUMN_NAME" -- the column name which the rule should be applied match="xxx" -- the key which the rule defines to filter and the result should match required="0|1" -- if 1, the result collection has to meet this rule or return nothing /> <rule .... </filter> */ @column varchar(100) ) RETURNS @returntable TABLE ( [Match] nvarchar(100), [Required] bit ) AS BEGIN ;with tmp as ( select [T].[RULE].value('@column','varchar(100)') as [Column], [T].[RULE].value('@match','nvarchar(100)') as [Match], [T].[RULE].value('@required','bit') as [Required] from @filter.nodes('filter//rule') [T]([RULE]) ) INSERT @returntable select [Match],[Required] from tmp where [Column] = @column RETURN END
/* PROCEDURE: [dbo].[sp_r_fp_configuration] OPERATION: READ FEATURES: Paginate, Filter PURPOSE: provide a paginated & filterable list from the configuration table CREATOR: Jerry Weng CREATETIME: 2014-4-9 UPDATETIME: 2014-4-9 VERSION: 1.0 */ CREATE PROCEDURE [dbo].[sp_r_fp_configuration] @pageIndex int = 1, /*which page of the total page*/ @pageSize int=10, /*how many records show in one page*/ @filter xml, /*filter string for the records*/ @recordCount int OUTPUT, /*output: return the count of the total records in all pages*/ @pageCount int OUTPUT /*output: return the count of the total pages*/ AS if(@filter is null) begin exec dbo.sp_r_p_configuration @pageIndex, @pageSize, @pageCount=@pageCount OUTPUT, @recordCount=@recordCount OUTPUT end else begin declare @tmptbl table (row_id int, Id int, [Key] varchar(100), [Value] varchar(200)) declare @startRow int; -- the row number of the first record in the page declare @endRow int; -- the row number of the last record in the page set @startRow = (@pageIndex - 1) * @pageSize + 1; set @endRow= @startRow + @pageSize - 1; insert into @tmptbl select (ROW_NUMBER() over (order by m.Id)) as row_id, m.[Id], m.[Key], m.[Value] from dbo.Configuration as m outer apply fun_xmlfilter_parse(@filter,'key') as k outer apply fun_xmlfilter_parse(@filter,'value') as v where ( not (isnull(k.[Required],0)=0 and isnull(v.[Required],0)=0) and (isnull(k.[Required],0)=0 or (k.[Required] = 1 and isnull(m.[Key],'') = isnull(k.[Match],''))) and (isnull(v.[Required],0)=0 or (v.[Required] = 1 and isnull(m.[Value],'') = isnull(v.[Match],''))) ) or k.[Required] = 0 and isnull(m.[Key],'') = isnull(k.[Match],'') or v.[Required] = 0 and isnull(m.[Value],'') = isnull(v.[Match],'') select [Id], [Key], [Value] from @tmptbl where row_id between @startRow and @endRow -- calculate the record count in all pages select @recordCount=COUNT(*) from @tmptbl -- calculate the page count set @pageCount = CEILING(@recordCount/CAST(@pageSize as float)) end RETURN 0
這里用了一個表變量,注意表變量是可被緩存的,臨時表沒有哦,用表變量不用with...as是因為后面在計算過濾后的總記錄數(shù)的時候,還需用一次過濾后的集合。這里我希望列Key和列Value都可以被過濾,于是用了兩個outer apply來將剛才那個函數(shù)的輸出表附加到每行上,在where比較的地方,先比較Required是1的必要條件,當(dāng)然如果針對某個column沒有rule的話,也就是required is null的情況,是需要排除的,最后再附加連個required=0的可選條件,這樣的話,一個select就可以把各種條件過濾出來了。不過,有個問題是,如果需要過濾的列比較多,那比較語句也要一條條加上去。
最后,來測試下:
我給表填充了這么些數(shù)據(jù):
SET IDENTITY_INSERT [dbo].[Configuration] ON INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (1, N'test1', N'123') INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (2, N'test2', N'123') INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (3, N'test3', N'567') INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (4, N'test4', NULL) INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (5, N'test5', NULL) INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (6, N'test6', NULL) INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (7, N'test7', NULL) INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (8, N'test8', NULL) INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (9, N'test9', NULL) INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (10, N'test10', NULL) INSERT [dbo].[Configuration] ([Id], [Key], [Value]) VALUES (11, N'test11', NULL) SET IDENTITY_INSERT [dbo].[Configuration] OFF
測試腳本:
declare @pageIndex int; set @pageIndex=1; declare @pageSize int; set @pageSize=5; declare @filter xml; set @filter='<filter><rule column="key" match="test3" required="1"/><rule column="value" match="123" required="0"/></filter>' declare @pageCount int; declare @recordCount int; exec dbo.sp_r_fp_configuration @pageIndex,@pageSize,@filter,@pageCount=@pageCount OUTPUT, @recordCount=@recordCount OUTPUT select @pageCount as [PAGECOUNT], @recordCount as [RECORDCOUNT]
輸出,如果需要找null值的話,直接把match屬性去掉就可以了<rule column="value" required="1"/>:
來自: 昵稱10504424 > 《工作》
0條評論
發(fā)表
請遵守用戶 評論公約
sql2000和sql2005分頁存儲過程
SQL查詢拼接存儲過程 分頁
ALTER PROCEDURE [dbo].[usp_apiUser] @Account varchar(50)='''', @BeginTime varchar(50)='''',--...
NHibernate使用Criteria分頁顯示并返回記錄總數(shù) - loya的專欄 - C...
//設(shè)置分頁 criteria.SetFirstResult( (currentPageIndex.Value-1) * pageSize.Value ) .SetMaxResults( pageSize.Value ); return criteria.List( ); ...
SqlServer 數(shù)據(jù)分頁的存儲過程--我的窩
SELECT TOP 頁大小 *FROM TestTableWHERE (ID NOT IN (SELECT TOP 頁大小*頁數(shù) id FROM 表 ORDER BY id))ORDER BY ID.通過SQL 查詢分析器,顯示比較:我的結(jié)論是:分頁方案二...
ASP.NET自定義控件:實現(xiàn)分頁功能的DataList(10)_設(shè)計家園
在ASP.NET中DataList可以實現(xiàn)數(shù)據(jù)展示,我們可以通過定制其模版實現(xiàn)豐富的格式,但是美中不足的時DataList默認(rèn)情況下不支持分頁,我們當(dāng)然可以編寫一個用戶控件以實現(xiàn)分頁功能,但是這種方案仍然不是很...
高效分頁存儲過程
BEGIN SET @SortTypeB='' DESC '' SET @sortTypeA='' ASC '' ENDIF @fieldSort IS NOT NULL AND @fieldSort<>'''' --排序字段不為空時 BEGIN...
最高效的分頁存儲過程
最高效的分頁存儲過程。set @SelectSql = '' select @RecordCount = count(0) from '' + @TableName + '' where '' + @Where.exec sp_executesql @SelectSql ,N'&...
JavaScript分頁代碼
var minNum=new GetNumArea(currentPage,numCount,pageCount).minNum;var maxNum=new GetNumArea(currentPage,numCount,pageCount).maxNum;//顯示分頁數(shù)字 結(jié)束 CreateHref(url,new GetNumArea(current...
DWR整合SSH
微信掃碼,在手機上查看選中內(nèi)容