亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

那些可以在數據庫里做的事:分頁與過濾

2024-07-21 02:50:28
字體:
來源:轉載
供稿:網友
那些可以在數據庫里做的事:分頁與過濾

其實很多非業務邏輯的功能,比如分頁,數據過濾,可以在程序上面節省很多內存和CPU時間,但往往又找不到一個比較通用有效的方法,花了點時間,終于把我想要的在數據庫中分頁和過濾的功能寫了出來,在這里分享。

第一期望:我希望輸入頁碼(pageIndex),每頁顯示的記錄數(pageSize),然后這個存儲過程就可以給我一個當前頁的數據集。

首先,我假設有個表叫Configuration,里面就3個字段,Id, Key, Value,就是一個簡單的數據表,定義如下:

CREATE TABLE [dbo].[Configuration](    [Id] int NOT NULL IDENTITY (1,1),     [Key] varchar(20) NOT NULL UNIQUE,    [Value] nvarchar(max) NULL)

然后,就可以寫存儲過程了,這里想要說下,我對存儲過程命名的一些習慣,我會以"sp_"開頭,為了標明這個存儲過程是CRUD中的哪個操作,我會再附加一個縮寫,比如這個分頁的主要操作時READ,所以我的名字應該是"sp_r_",然后為了說明它的主要功能是分頁,就有了"sp_r_p_",“p”表示paginate,最后跟上操作的主要的表名,"sp_r_p_configuration"。很多同學都喜歡用比如bypage等等,也可以,但是我更喜歡這種命名法,在特定的約定下,這種簡潔性的命名可可讀性。再者,一個良好的代碼書寫規范是非常必要的,該注釋的地方千萬別省,在多數情況下,代碼的可讀性是非常重要的,除非因性能因素做必須得讓步。

/*PROCEDURE:    [dbo].[sp_r_p_configuration]OperaTION:    READFEATURES:        PaginatePURPOSE:        provide a paginated list from the configuration tableCREATOR:        Jerry WengCREATETIME:    2014-4-9UPDATETIME:    2014-4-9VERSION:        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()來實現分頁,性能必拼SQL的方法好,WITH...AS可以省下一個表變量。最后計算總記錄數和頁數很簡單,算下就好了。

第二期望:這樣的,似乎差不多了,但是我還希望能夠有一套規則,來過濾結果集,并且還要有類似AND和OR的運算功能,而且我仍舊不希望用inline-script去實現,能不用盡量不要用。

為了實現這個期望,我需要先定義怎么傳入過濾規則,我最終決定用的是xml數據類型而不是普通字符串,因為普通字符串有長度限制(如果你說可以用text,那我只能說太奢侈,小弟用不起),定短了可能被截斷出現錯誤輸出,定長了,最多也就8000個字符,也浪費,我不喜歡不確定因素,然而xml不一樣,既是結構化數據,又有索引支持,可長可短,客戶端也可直接序列化成字符串傳入,非常方便。于是剩下的是,約定一個規則,確定過濾規則的數據結構,在這里我專門寫了一個function來將xml轉換成table已被后用。P.S. 如果想傳一個數組到存儲過程,也可以用xml類型,比字符串加分隔符更安全。

/*FUNCTION:        [dbo].[fun_xmlfilter_parse]OPERATION:    READFEATURES:        PURPOSE:        parse a table from a xml with the specific column nameCREATOR:        Jerry WengCREATETIME:    2014-4-9UPDATETIME:    2014-4-9VERSION:        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)ASBEGIN    ;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

xml的結構由一個根節點<filter>開始,里面是多個<rule>節點,具體的規則定義在rule的屬性列表中。column表示具體要過濾哪列的數據,match表示要匹配的數據值,比如我想要過濾列"Value"下,值為"sample"的數據,這樣的話我只需要把xml寫成<filter><rule column="value" match="sample"required="1"/></filter>,最后的哪個required就是來實現AND和OR的操作的,如果是1表示必須匹配,類似AND,0的話可選匹配,類似OR,輸出的表示由COLUMN的值過濾過的,因為比較是以COLUMN為維度的。

最后,新建一個存儲過程,叫"sp_r_fp_configuration",這里比上一個多了一個"f",表示帶有過濾功能。

/*PROCEDURE:    [dbo].[sp_r_fp_configuration]OPERATION:    READFEATURES:        Paginate, FilterPURPOSE:        provide a paginated & filterable list from the configuration tableCREATOR:        Jerry WengCREATETIME:    2014-4-9UPDATETIME:    2014-4-9VERSION:        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))    endRETURN 0

這里用了一個表變量,注意表變量是可被緩存的,臨時表沒有哦,用表變量不用with...as是因為后面在計算過濾后的總記錄數的時候,還需用一次過濾后的集合。這里我希望列Key和列Value都可以被過濾,于是用了兩個outer apply來將剛才那個函數的輸出表附加到每行上,在where比較的地方,先比較Required是1的必要條件,當然如果針對某個column沒有rule的話,也就是required is null的情況,是需要排除的,最后再附加連個required=0的可選條件,這樣的話,一個select就可以把各種條件過濾出來了。不過,有個問題是,如果需要過濾的列比較多,那比較語句也要一條條加上去。

最后,來測試下:

我給表填充了這么些數據:

SET IDENTITY_INSERT [dbo].[Configuration] ONINSERT [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].[Configur
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产一区欧美二区三区| 国内精品免费午夜毛片| 国产精品欧美日韩一区二区| 在线视频日本亚洲性| 欧美一区二区三区图| 国产日韩换脸av一区在线观看| 欧美专区第一页| 日本精品久久中文字幕佐佐木| 91视频国产高清| 日韩少妇与小伙激情| 日韩av在线一区二区| 91日韩在线播放| 91精品国产免费久久久久久| 欧美性xxxx极品高清hd直播| 日韩精品在线视频美女| 亚洲а∨天堂久久精品喷水| 亚洲free性xxxx护士白浆| 一本色道久久88综合亚洲精品ⅰ| 欧美成人午夜免费视在线看片| 亚洲电影免费观看高清完整版在线观看| 九九热最新视频//这里只有精品| 欧美性理论片在线观看片免费| 亚洲国产成人在线视频| 欧美在线播放视频| 久久精品久久久久久国产 免费| 8x海外华人永久免费日韩内陆视频| 91影视免费在线观看| 日韩中文字幕免费| 亚洲第一天堂无码专区| 亚洲片在线观看| 精品综合久久久久久97| 日本久久久久久久久久久| 成人观看高清在线观看免费| 欧美国产日韩二区| 在线观看精品自拍私拍| 亚洲国产私拍精品国模在线观看| 亚洲第一精品夜夜躁人人爽| 亚洲精品国产精品自产a区红杏吧| 亚洲另类xxxx| 国产亚洲欧美aaaa| 全色精品综合影院| 精品日韩中文字幕| 国产日韩中文在线| 日韩电影免费观看在线| 狠狠色香婷婷久久亚洲精品| 韩剧1988在线观看免费完整版| 日韩极品精品视频免费观看| 欧美专区日韩视频| 国产精品一区二区久久久| 亚洲精品aⅴ中文字幕乱码| 精品久久久久久久久中文字幕| 欧美最猛性xxxx| 爽爽爽爽爽爽爽成人免费观看| 国产日韩欧美黄色| 亚洲成人aaa| 久久久日本电影| 成人a级免费视频| 欧美黄色www| 国产精品96久久久久久又黄又硬| 欧美极品欧美精品欧美视频| 久久久97精品| 欧美日本黄视频| 97在线观看免费| 欧美人在线观看| 中文欧美日本在线资源| 亚洲国产福利在线| 国产成人黄色av| 中文字幕亚洲国产| 黑人巨大精品欧美一区二区一视频| 国产精品免费久久久久影院| 国产精品久久久久久久久久久久久久| 亚洲**2019国产| 国产精品综合网站| 亚洲第一免费播放区| 成人黄色在线观看| 欧美中文字幕在线播放| 欧美xxxx14xxxxx性爽| 亚洲在线一区二区| 欧美成人黄色小视频| 日本高清视频精品| 一个人看的www欧美| 成人精品一区二区三区电影免费| 欧美性猛交xxxx乱大交| 亚洲电影成人av99爱色| 青青草国产精品一区二区| 日韩在线视频观看正片免费网站| 欧美激情精品久久久久久久变态| 欧美自拍大量在线观看| 中文国产成人精品| 亚洲成人av在线| 欧美一区二区影院| 亚洲人成免费电影| 久久久电影免费观看完整版| 国产欧美精品一区二区三区-老狼| 中文字幕日韩av电影| 欧美性猛交xxxx富婆| 国产亚洲精品久久久久动| 日本久久中文字幕| 欧美wwwxxxx| 亚洲影院高清在线| 亚洲国产精品高清久久久| 亚洲一区二区国产| 亚洲国产精品视频在线观看| 国产精品欧美激情在线播放| 深夜精品寂寞黄网站在线观看| 国产日韩在线一区| 亚洲韩国日本中文字幕| 国产精品一久久香蕉国产线看观看| 精品美女国产在线| 亚洲无亚洲人成网站77777| 疯狂做受xxxx欧美肥白少妇| 中文字幕av一区| 久久免费视频这里只有精品| 91精品国产乱码久久久久久蜜臀| 欧美专区国产专区| 亚洲精品动漫100p| 亚洲自拍偷拍在线| 亚洲成人精品视频在线观看| 成人美女免费网站视频| 国产亚洲欧美日韩一区二区| 97国产精品视频| 亚洲精品久久久久国产| 国产日韩在线免费| 亚洲第一区中文99精品| 自拍偷拍亚洲在线| 欧美一级视频一区二区| 欧美精品videos| 欧美日韩性视频| 91久久精品视频| 国产美女高潮久久白浆| 日韩美女在线观看| 久久视频免费观看| 国产精品极品美女在线观看免费| 7m精品福利视频导航| 久久久国产成人精品| 国产精品久久久久久搜索| 亚洲精品动漫100p| 欧美激情一区二区三区在线视频观看| 亚洲一区二区黄| 日韩精品中文字幕有码专区| 亚洲成人动漫在线播放| 欧美老女人性生活| 亚洲第一页在线| 国产精品成人av性教育| 国产精品永久免费视频| 国产精品极品美女粉嫩高清在线| 中文字幕国产精品| 亚洲加勒比久久88色综合| 日韩成人网免费视频| 国产精品第三页| 97av在线播放| 欧美大胆在线视频| 91老司机精品视频| 蜜臀久久99精品久久久无需会员| 日韩精品久久久久久福利| 欧美成人三级视频网站| 国产欧美日韩丝袜精品一区| 欧美精品一区在线播放| 亚洲人成伊人成综合网久久久| 欧美日韩精品中文字幕| 91天堂在线观看| 国产精品久久网| 亚洲精品电影久久久| 欧美日韩国产专区|