用正则简化分页函数

天界王者 发布于 2012/12/14 11:55
阅读 983
收藏 10

看过不少分页函数,都把统计记录数COUNT分开单独写,像我这样的懒人来说,能少打一个字,那绝对不会多动一个指头,就好比即使桌子上有一包瓜子,如果没开封,我是懒的去开了封来吃的,当然如果有人开了除外。

因为统计记录数的SQL语句与查询的SQL语句,除了SELECT与FROM中间不同之外,其它是一致的,这样只要用正则替换掉查询语句的中间部分就足够了,调用之时,每次只需写查询语句而不用去关心COUNT,这样即使查询条件变动了也不会出现COUNT中的查询条件忘记修改而出现错误的分页结果。

正则替换如下:

Regex regExp = new Regex(@"select\s+.*\s+from\s+", RegexOptions.IgnoreCase);
string countSQL = regExp.Replace(sql, "SELECT COUNT(1) FROM ");
下面是我在使用中的完整示例,针对Postgres的,但是这种处理方式在任何语言、任何数据库查询处理中皆可参照。

/// <summary>
        /// 分页
        /// </summary>
        /// <param name="sql">SELECT * FROM table WHERE col1=:1 AND col2=:2</param>
        /// <param name="pageNo"></param>
        /// <param name="pageSize"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static DataPager ExecutePager(string sql, int pageNo, int pageSize, params object[] args)
        {
            Regex regExp = new Regex(@"select\s+.*\s+from\s+", RegexOptions.IgnoreCase);
            string countSQL = regExp.Replace(sql, "SELECT COUNT(1) FROM ");
            long total = ExecuteScalar<long>(countSQL, args);
            int startIndex = pageSize * (pageNo - 1);
            sql += string.Format(" LIMIT {0} OFFSET {1} ",pageSize,startIndex);
            DataTable table = ExecuteDataTable(sql,args);
            DataPager dp = new DataPager();
            dp.Total = total;
            dp.ResultSet = Utils.ToList(table);
            return dp;
        }
        /// <summary>
        /// 命名参数分页
        /// </summary>
        /// <param name="sql">SELECT * FROM table WHERE col1=:paramName1 AND col2=:paramName2</param>
        /// <param name="pageNo"></param>
        /// <param name="pageSize"></param>
        /// <param name="paramValues"></param>
        /// <returns></returns>
        public static DataPager ExecutePager(string sql, int pageNo, int pageSize, Dictionary<string, object> paramValues)
        {
            Regex regExp = new Regex(@"select\s+.*\s+from\s+", RegexOptions.IgnoreCase);
            string countSQL = regExp.Replace(sql, "SELECT COUNT(1) FROM ");
            long total = ExecuteScalar<long>(countSQL, paramValues);
            int startIndex = pageSize * (pageNo - 1);
            sql += string.Format(" LIMIT {0} OFFSET {1} ", pageSize, startIndex);
            DataTable table = ExecuteDataTable(sql, paramValues);
            DataPager dp = new DataPager();
            dp.Total = total;
            dp.ResultSet = Utils.ToList(table);
            return dp;
        }

加载中
0
迷路的游侠
迷路的游侠
原来每次改查询代码时,需要两个方法一起改,这下似乎有解决方案了,膜拜楼主
0
南湖船老大
南湖船老大

贴另外一种思路。

@Override

    protected String buildPageSql(String sql, int from, int pageSize) {

        sql = removeSelect(sql);

        return "select SQL_CALC_FOUND_ROWS " + sql + " limit " + from + ", " + pageSize;

    }

    /** Returns FOUND_ROWS() sql to determine total count of founded rows.

    */

    @Override

    protected String buildCountSql(String sql) {

        return "SELECT FOUND_ROWS()";

    }

0
Y-QTCe
Y-QTCe

.NET代码我不太懂,不过对于正则,一般有些常见的问题,不知道楼主这里是怎么处理的。比如说这样一句SQL:

 select a.cola, a.colb from (select cola, count(*) colb from b where b.cola = 1 group by b.cola) a


天界王者
天界王者
回复 @Y-QTCe : 经测试确实如此,我也是奇怪了,语法上说不过去,但是又选中了,那我能想到的剩下的只有两种方案:1,排除()内的select from,2,平衡组或者像语法着色一样成对查找,平衡组不熟悉,可以用语法着色方式,但要保证select与from是成对的,不知道会否有例外,第一种还没有试过
Y-QTCe
Y-QTCe
回复 @tinyms : 你这个不对吧…… [^select] 的意思我记得是说非 's' 'e' 'l' 'e' 'c' 't'这几个字母,而不是说非“select" 这样一个词。对应到这里,恰好我用了 from c,它要非'c',所以才把这部分划归到前面的 .*? 里面去了,这样才通过的。你可以试下把 from c 改成 from x 之类的,看看是什么结果?
天界王者
天界王者
^\s*select\s+.*?[^select]\s+from\s+,这样可以选择出来,但是我怕还是没有处理到所有情况,考虑应该以分析成对标签的方式来处理,暂时还没测试成功,再一个通常这种多表操作会用视图来简化,如果已经有更准确的正则表达式,一定要分享下,哈哈
Y-QTCe
Y-QTCe
回复 @tinyms : 那再来一个: select a.cola, (select c.colc from c ) as colb from a
天界王者
天界王者
非常非常感谢Y-QTCe提出的最短匹配问题,上面的正则表达式不能处理这个,所以把上面的正则表达式改成这个select\s+.*?\s+from\s+,中间多出一个?就可以只取最短的select from,这个在QT中是比较方便的,有一个最短匹配选项,谢谢让我完善了程序,如果还有其它情况,可以的话,也请帮忙举例,^_^
返回顶部
顶部