SQL Server 2005之后,令人困扰的分页问题似乎有了进展,那就是用ROW_NUMBER(),典型的语句如下SELECT
*
Talk: 对40万条记录的表与2万条记录的两个表inner
join 联合查询,应用 SQL code SELECT TOP 页大小
* FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1 ) A WHERE RowNumber > 页大小*(页数-1)
SQL code SELECT TOP 页大小
* FROM ( SELECT top 页大小*(页数)
ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1 ) A WHERE RowNumber > 页大小*(页数-1) 修改查询语句为如下形式,也是一样 SQL code SELECT TOP 页大小
* FROM ( SELECT top 页大小*(页数)
ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,col1,col2,col3,col4 FROM table1 ) A WHERE RowNumber > 页大小*(页数-1) 在刚出来工作时! 大多数人只知道用rownum 来进行分页,或是sql嵌套来分页
--话外题: 取n到m条记录的语句 1. select top m * from tablename where id not in (select top n id from tablename) 2. select top m * into 临时表(或表变量) from tablename order by columnname -- 将top m笔插入 set rowcount n select * from 表变量
order
by
columnname desc 3. select top n * from (select top m * from tablename order by columnname) a order by columnname desc 4.如果tablename里没有其他identity列,那么: select identity(int) id0,* into #temp from tablename 取n到m条的语句为: select * from #temp where id0 >=n and id0 <= m 如果你在执行select identity(int) id0,* into #temp from tablename这条语句的时候报错,那是因为你的DB中间的select into/bulkcopy属性没有打开要先执行: exec sp_dboption 你的DB名字,'select into/bulkcopy',true 5.如果表里有identity属性,那么简单: select * from tablename where identitycol between n and m 如果是sql server 2005 可以这样写:
select top 20 * from T order col except select top 2 * from T order col --话外题2:--方法1: --适用于 SQL Server 2000/2005 SELECT TOP 页大小 * FROM table1 WHERE id NOT IN ( SELECT TOP 页大小*(页数-1) id FROM table1 ORDER BY id ) ORDER BY id --方法2: --适用于 SQL Server 2000/2005 SELECT TOP 页大小 * FROM table1 WHERE id > ( SELECT ISNULL(MAX(id),0) FROM ( SELECT TOP 页大小*(页数-1) id FROM table1 ORDER BY id ) A ) ORDER BY id --方法3: --适用于 SQL Server 2005 SELECT TOP 页大小 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1 ) A WHERE RowNumber > 页大小*(页数-1) --方法四 适用于 SQL Server 2005 DECLARE @pagenum AS INT, @pagesize AS INT SET @pagenum = 2 SET @pagesize = 3 SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY newsid DESC) AS rownum, newsid, topic, ntime, hits FROM news) AS D WHERE rownum BETWEEN (@pagenum-1)*@pagesize+1 AND @pagenum*@pagesize ORDER BY newsid DESC 说明,页大小:每页的行数;页数:第几页。使用时,请把“页大小”和“页大小*(页数-1)”替换成数字。 --题外话3 ROW_NUMBER()函数是Sql 2005中新添的一个函数。通常它被用在分页的SQL语句中。 微软官方的对此函数的描述是:返回结果集分区内行的序列号,每个分区的第一行从 1 开始。 我对此的理解:利用此函数可以为表中的某个字段建立序列,从1开始。就是说,根据已存在的某列,利用此函 数可建立一新列,新列是数字,按照已存在列的顺序从1开始。 上边可能说的不是很 清楚,请结合下边这个例子来看吧!
第一个 查询只是一个普通的查询,查询出Orders表中的3个字段的记录。其结果为: 第二个查询相比第一个查询仅仅是多了“ ROW_NUMBER() OVER(ORDER BY orderID DESC) AS 字段编号 ”这段语句。我们来分析一 下这段语句。 这 段语句的作用就是利用ROW_NUMBER()函数根据OrderID这列来生成一个新的数据列,这列的名称为字段编号。然后我们根据ORDER BY orderID DESC来指定字段编号这列按照
OrderID的逆序来生成,结果如下: 比较两个结果集,会发现第二个结果集是按照OrderID字段逆序的记录,其实也可看成是字段编号这个字段 的正序排序,ROW_NUMBER()函数相当于为SELECT语句末尾加了ORDER BY子句,第二个SELECT语句其实等价于:
下边来看一个对ROW_NUMBER()函数的简单分页应用。
首先把应用ROW_NUMBER()函数后的结果集存在一张临时表中,然后以字段编号这个字段为条件,使用BETWEEN关键字过滤相应的记录。 --题外话4: 日前為了解決公司系統效能的問題,真的是挖了不少解決方案出來,其中一個比較有意思的就是分頁處理. 分頁方式其實有非常的多種,例如 把資料全部丟到Web,再分頁顯示,或是直接在DataAdapter.Fill時,下筆數,或是用Selete top 加上一些過濾及排序等動作. 但 這些做法,都不能解決我現在的頻寬問題,因為分店連回總公司只有2M/256K的頻寬,如果一次倒回大量的資料,一定會打爆網路,而總公司的架構部 份,WebService與DataBase也是不同台的伺服器,兩台伺服器也是需透過網路來傳輸,所以思考方向會是在如何在DataBase那,就做好 分頁的動作. 不要有大量的資料在網路上傳輸. 為了這個問題,找了不少方法,像是Select top的方式,但因為程式查詢彈性的關係,造成這部份的邏輯相當的複雜,效能也不好. 最後找到SQL 2005才有的Row_number()這個Function可以用. 從一些參考網站所做的效能評比中,也算是數一數二的做法,所以這做法也是最後被公司採用的解決方案. 以下就是說明Row_number() 的基本做法. select a.UserName,a.UserID from (select row_number() over (order by UserID) as UID,UserName,UserID from UserDataInfo where bmi>20) as a where a.UID between @SP and @EP 這段語法就是關鍵所在, 正常來說,我的語法只有紅字部份,帶出所有bmi>20的人員,一次把資料全部回傳, 但這裡卻多了一段藍字在裡面,Row_Number()就是將符合條件的結果,再從1開始, 依序給予編號,所以回傳的結果就會是 UID UserName UserID 1 Jeff A0001 2 Jerry C0014 3 Judy C0096 4 Mark D0002 5 Jason D0010 6 Rober D0011 7 Martin D0022 所 以黑色部份的語法,就依這個的查詢結果,取出UID介於幾號到幾號之間. 所以就可以在DataAccess端,依據設定的PageSize,來算頁次,再依目前的頁次與PageSize去帶回所需顯示的資料範圍. 如 果不分頁的話,一次載入上萬筆資料是很可怕的,尤其是透過2M/256K的頻寬,這是ERP系統,不是P2P下載平台,使用者不可能等,如果用分頁方式, 就只會一次傳回指定的筆數,大幅的減少網路的負擔,而且這是在DB就做好的動作,所以從DataBase到WebService這段的網路問題也解決了. 這 做法也不是沒有缺點,例如在換頁過程中,突然又有幾筆資料符合或不符合了,其順序就會異動,就有可能剛好在換頁時,某筆資料會沒看到,可能跳到前頁或下頁 去了. 這部份就看各家使用者了. 另一個問題就是筆數一多時,頁次愈換到後面,速度會愈慢,但這也是百萬筆資料的事,當有這麼多資料時,應 該也沒有什麼人會一頁一頁的去看完它. Row_number()更多的說明,參考MSDN 或是GOOGLE大神
2008/10/17補充 : Oracle可以用Rownum的方式取代 Row_number() |
|