Sign-up....

求一通用分页SQL(不要存储过程)(C#实现)

要实现这么一个功能的函数:

输入参数:一个取得记录集的Select SQL,开始行行号,最大返回行数,唯一键列名

返回:返回一个基于给出的SQL的分页SQL

我实现的一个函数如下:

/// <summary>

/// 执行SQL查询,返回分页记录集

/// </summary>

/// <param name="sql">SQL语句</param>

/// <param name="startRowIndex">开始行,1开始</param>

/// <param name="maximumRows">最大返回行数</param>

/// <param name="keyColumn">主键列。用于not in分页</param>

/// <returns></returns>

public virtual DataSet Query(String sql, Int32 startRowIndex, Int32 maximumRows, String keyColumn)

{

// 从第一行开始,不需要分页

if (startRowIndex <= 1)

{

if (maximumRows < 1)

return Query(sql);

else

return Query(String.Format("Select Top {0} * From ({1}) a", maximumRows, sql));

}

if (maximumRows < 1)

sql = String.Format("Select * From ({1}) b Where {2} Not In(Select Top {0} {2} From ({1}) a)", startRowIndex - 1, sql, keyColumn);

else

sql = String.Format("Select Top {0} * From ({1}) b Where {2} Not In(Select Top {3} {2} From ({1}) a)", startRowIndex + maximumRows - 1, sql, keyColumn, startRowIndex - 1);

return Query(sql);

}

在实际应用中发现,对于Access,该方法可行,对于MSSQL,就不一定了。

如果参数中的sql带有order by,而又没有top,那么,这个SQL是不能作为子查询的,上面的方法就行不通了。

后来我又加了下面一个函数:

/// <summary>

/// 为子查询准备。

/// 如果一个SQL用了order by,而没有top时,在SqlServer中是不能作为子查询的。

/// </summary>

/// <param name="sql"></param>

/// <returns></returns>

private String PrepairSqlForSubSelect(String sql)

{

String str = sql.Trim().ToLower();

// Select开头,不是存储过程

if (str.StartsWith("select ") && str.Contains("order by"))

{

str = str.Substring(0, 30);

if (!Regex.IsMatch(str, @ "^ *select( +(all|distinct))? +top ", RegexOptions.IgnoreCase))

{

sql = Regex.Replace(sql, @ "^ *select +all ", "Select All Top 100000000 ", RegexOptions.IgnoreCase);

sql = Regex.Replace(sql, @ "^ *select +distinct ", "Select Top 100000000 ", RegexOptions.IgnoreCase);

sql = Regex.Replace(sql, @ "^ *select +", "Select Top 100000000 ", RegexOptions.IgnoreCase);

}

}

return sql;

}

用来检查参数sql是否是这种情况,如果是的话,用正则修改这个sql,在select后面加上Top 100000000。可以解决一部分问题。

后来又发现,如果参数sql中,select后面的选择列中带有ntext类型字段的话,是不能用top。

我现在没办法了,请各位帮帮忙。

存储过程的方法就不用啦,谢谢^_^

[2076 byte] By [天涯浪人] at [2007-8-15 11:07:26]
# 1 Re: 求一通用分页SQL(不要存储过程)(C#实现)
呵呵,楼上的做法,和我现在的想法一直,就是做一个sql生成类,但是,这样有一个极大的缺点,只能用于简单的语句生成,一些非常复杂而又需要用到分页的语句,就无能为力了。

谢谢楼上的

dfgsdfg at 2007-2-26 20:50:53 >
# 2 Re: 求一通用分页SQL(不要存储过程)(C#实现)
呵呵,楼上的,不好意思,要是取出来才分页,那可就……

你知道我表里面多少数据么?

一千万,不是很多,呵呵

叛乱 at 2007-2-26 20:51:17 >
# 3 Re: 求一通用分页SQL(不要存储过程)(C#实现)
select Topic from (select top " + perPage + " ID,Topic from (select top " + currentPage * perPage + " ID,Topic from ForumList order by ID asc) as A order by ID desc) as B order by ID asc

currentPage ---当前页码

perPage ---每页记录数

[顾问团]寻开心 at 2007-2-26 20:51:25 >
# 4 Re: 求一通用分页SQL(不要存储过程)(C#实现)
我的要求是这样的,我要求业务层写普通的查询语句,传到数据层的时候,由数据层处理。数据层是支持多数据库的。由于业务层只写普通的查询语句,所以很容易写出各个数据库平台都通用的查询语句,并且,在业务层,也不该意识到数据库方言的差异。

业务层只写普通的查询语句 ---- 你这样分层不太合理吧?(个人意见)

损人专家 at 2007-2-26 20:51:41 >
# 5 Re: 求一通用分页SQL(不要存储过程)(C#实现)
@ nikolas

大部分情况下,都是业务层调用数据层,但是有时候,业务层的更上一层,可能会需要直接调用数据层,以实现某些特殊的功能,所以,不能把业务层的处理移到数据层。

◎jyk

我也想这么做,但是,你可有发现,这么做,只能实现非常简单的语句而已,带有组合查询、子查询等负责的语句,就无能为力了,我曾试过想按照TSQL92的标准来分析,发现,太复杂了,所以不了了之。

我就是想封装好数据层,使用数据层的,不仅仅是业务层呀,所以数据层不能做成只为业务层服务。

我没当大哥很久了....... at 2007-2-26 20:51:57 >
# 6 Re: 求一通用分页SQL(不要存储过程)(C#实现)
if(currPage==1)

{

strSql=String.Format("Select Top {0} * From ({1}) a order by {2} {3}", pageSize, sql,keyColumn,OrderType);

}

-----------

有点小错误,才改了下

伤心小丑 at 2007-2-26 20:52:34 >
# 7 Re: 求一通用分页SQL(不要存储过程)(C#实现)
Erison写得很不错,要是能够更通用就好了,呵呵。

如果参数sql里面,有order by而没有top,你还是一样会犯我那样的错误的。

你只不过是把我的not in改为两个top来提高性能而已。

不过还是要谢谢你。

幸运的我 at 2007-2-26 20:52:40 >
# 8 Re: 求一通用分页SQL(不要存储过程)(C#实现)
我的思路是:一种数据库对应一个数据访问层。

1、要想提高分页的效率就得根据数据库的特性来做,MSSQL是对top 支持的“最好”的,而利用这个top 加上单一主键,就可以实现很高的效率和通用性,而这种方法对于SQLanywhere 就不行,因为他不支持top嵌套。据说orcale根本就不支持top (我一点都不会orcale,所以也不知道我说的对不对)。其它的数据库也是不一样的。

听说 SQL2005又加了一个新的东东,可以利用这个来分页了,同一种数据库不同的版本都会有不同的情况,所以说想通用是很能的,想即通用又高效又支持各种数据库,那更是难上加难。

C/C++

All Classified