百度一下,发现N多万能的sql分页办法, 不过大都有一个共性,就是把一段sql的各个部分折成几个参数,然后拼接sql
而且很多都只支持单表.
我发的代码就是为了解决上面这两个问题的.
使用注意事项:
1.传入的sql必须是可以正常执行的sql
2.传入的sql必须有排序(order by )
3.如果使用的是SqlServerDialect,最好传入正确totalCount,否则最后一页的数据可能跟你想像中的不太一样,
如果是SqlServer2005Dialect的话,不存在此问题
4.基本上可以满足绝大部分的sql语句,大家可以试试复杂的sql,有兴趣的话,可以跟我联系,大家一起完善
下面这段是针对sql server 2000的,不过2005与2008一样可以用
public class SqlServerDialect:ISqlDialect
{
#region ISqlDialect 成员
public string GetPageSqlText(string sql, int pageSize, int pageNum, int totalCount)
{
if (string.IsNullOrEmpty(sql))
return sql;
string orderByText = GetOrderByText(sql);
if (string.IsNullOrEmpty(orderByText))
throw new ArgumentException("缺少order by ");
if (pageNum == 1)
return GetFirstPageSqlText(sql, pageSize);
int rowCount = pageSize;
if (totalCount > 0)
{
if (totalCount < pageNum * pageSize)
{
rowCount = totalCount - (pageNum - 1) * pageSize;
}
if (rowCount < 0)
rowCount = 0;
}
int pos = sql.IndexOf("select", StringComparison.OrdinalIgnoreCase);
if (pos < 0)
throw new ArgumentException("缺少select关键字", sql);
//string orderByText = GetOrderByText(sql);
string reverseOrderByText = GetReverseOrderByText(orderByText);
StringBuilder sb = new StringBuilder();
sb.AppendFormat("select * from ( select top {0} * from ( select top {1}", rowCount, pageSize * pageNum);
sb.Append(sql.Substring(pos + "select".Length));
sb.Append(") as temptable1 order by ");
sb.Append(reverseOrderByText);
sb.Append(") as temptable2 order by ");
sb.Append(orderByText);
return sb.ToString();
}
#endregion
private static string GetFirstPageSqlText(string sql, int pageSize)
{
int pos = sql.IndexOf("select", StringComparison.OrdinalIgnoreCase);
if (pos < 0)
throw new ArgumentException("缺少select关键字", sql);
StringBuilder sb = new StringBuilder(sql.Length + 20);
sb.Append(sql);
sb.Insert(pos + "select".Length + 1, String.Format("top {0} ", pageSize));
return sb.ToString();
}
private static string GetOrderByText(string sql)
{
int len = "order by".Length;
int pos = sql.LastIndexOf("order by", StringComparison.OrdinalIgnoreCase);
if (pos < 0)
{
return string.Empty; ;
}
return RemoveAlias(sql.Substring(pos + len));
}
private static string GetReverseOrderByText(string orderByText)
{
StringBuilder sb = new StringBuilder();
string[] cols = orderByText.Split(',');
for (int i = 0; i < cols.Length; i++)
{
if (i > 0)
sb.Append(",");
int pos = cols[i].LastIndexOf(" desc", StringComparison.OrdinalIgnoreCase);
if (pos > -1)
{
sb.Append(cols[i].Substring(0, pos)).Append(" asc");
}
else
{
pos = cols[i].LastIndexOf(" asc", StringComparison.OrdinalIgnoreCase);
if (pos > -1)
{
sb.Append(cols[i].Substring(0, pos)).Append(" desc");
}
else
{
sb.Append(cols[i]).Append(" desc");
}
}
}
return sb.ToString();
}
private static string RemoveAlias(string orderByText)
{
StringBuilder sb = new StringBuilder();
string[] cols = orderByText.Split(',');
for (int i = 0; i < cols.Length; i++)
{
if (i > 0)
sb.Append(",");
int pos = cols[i].IndexOf(".");
if (pos > -1)
{
sb.Append(cols[i].Substring(pos + 1));
}
else
{
sb.Append(cols[i]);
}
}
return sb.ToString();
}
}
接着来个sqlserver2005的
public class SqlServer2005Dialect : ISqlDialect
{
#region ISqlDialect 成员
public string GetPageSqlText(string sql, int pageSize, int pageNum, int totalCount)
{
if (string.IsNullOrEmpty(sql))
return sql;
string orderByText = GetOrderByText(sql);
if (string.IsNullOrEmpty(orderByText))
throw new SqlNullValueException("缺少order by ");
if (pageNum == 1)
return GetFirstPageSqlText(sql, orderByText, pageSize);
int startIndex = (pageNum - 1) * pageSize;
int endIndex = startIndex + pageSize;
int pos = sql.IndexOf("select", StringComparison.OrdinalIgnoreCase);
if (pos < 0)
throw new ArgumentException("缺少select关键字", sql);
StringBuilder sb = new StringBuilder();
sb.Append(sql);
sb.Insert(pos + "select".Length + 1, String.Format(" top 100 percent row_number() OVER(order by {0}) AS _rowNum, ", orderByText));
sb.AppendFormat(" ) select * from _pageSql where _rowNum between {0} and {1} ", startIndex + 1, endIndex);
sb.Insert(0, "with _pageSql as ( ");
return sb.ToString();
}
#endregion
private static string GetFirstPageSqlText(string sql, string orderBySql, int pageSize)
{
int pos = sql.IndexOf("select", StringComparison.OrdinalIgnoreCase);
if (pos < 0)
throw new ArgumentException("缺少select关键字", sql);
StringBuilder sb = new StringBuilder(sql.Length + 20);
sb.Append(sql);
sb.Insert(pos + "select".Length + 1, String.Format("top {0} ", pageSize));
//sb.Append(" " + orderBySql);
return sb.ToString();
}
private static string GetOrderByText(string sql)
{
int len = "order by".Length;
int pos = sql.LastIndexOf("order by", StringComparison.OrdinalIgnoreCase);
if (pos < 0)
{
return string.Empty; ;
}
return sql.Substring(pos + len);
}
}
像oracle/sqlite/mysql的,就很简单,不发了.
顺便把接口也发一下
public interface ISqlDialect
{
string GetPageSqlText(string sql, int pageSize, int pageNum, int totalCount);
}