智能将SqlServer的查询语句转换为分页语句

主要用到了jsqlparser,前面有篇博客介绍过:

JAVA - Sql解析工具jsqlparser简单使用

为了给Mybatis分页插件增加对sqlserver的支持,专门写了这样一个独立的工具,只依赖jsqlparser。

这个类不仅是为了给分页插件使用的,他还能独立使用,使用它你可以方便的生成一个分页查询。

分页插件地址:Mybatis_PageHelper

SqlServer分页转换完整代码:com/github/pagehelper/SqlServer.java

简单讲一下处理的逻辑:

通过对SqlServer进行分析,利用jsqlparser方便的解析,然后对sql结构进行修改,生成最后的分页语句。

首先一个sql通常有两种情况,一种是普通的一个select查询,一种是通过union,minus等连接的多个查询。

当发现是多个查询的时候,会在原来的SQL基础上在外面包含一层查询,让原来的查询变成子查询。

外层的查询会从多个查询中的第一个查询中提取查询列(有别名的使用别名),因为每个查询的列都是一样的,所以找一个提取就行。

另外在多个SQL中的最后一个相比其他来说可能会多一些条件,这里主要考虑的是order by,如果有order by语句,会把order by移到外层SQL上。

做完上面的处理后,就和第一种普通的一个select查询一样了。

接下来处理这一个select查询。

第一步先获取查询列,并且会对别名和表名进行一些特殊处理。

第二步给SQL增加ROW_NUMBER(),将order by提取到OVER中

第三步处理全部子查询,如果子查询包含order by,会增加top 100 percent

第四步在select查询外包一层TOP查询。

经过上面的步骤就能得到一个合理结构的分页查询了。

其中有一些细节性的东西jsqlparser都考虑到了,不需要自己去特殊处理,例如distinct。

下面是两个例子。

这个类是独立的,使用的时候可以初始化一个,然后直接调用方法即可。

初始化:

public static final SqlServer sqlServer = new SqlServer();

第一个,多个查询UNION ALL

@Test
public void testSqlUnion() throws JSQLParserException {
    String originalSql = "select countryname,countrycode code from country where id >170 " +
            "union all " +
            "select countryname,countrycode code from country where id < 10 order by code";
    System.out.println(sqlServer.convertToPageSql(originalSql, 1, 10));
}

生成的SQL如下(经过人工格式化):

SELECT TOP 10 PAGE_TABLE_ALIAS.countryname, PAGE_TABLE_ALIAS.code
  FROM (SELECT ROW_NUMBER() OVER(ORDER BY code) PAGE_ROW_NUMBER,
               WRAP_OUTER_TABLE.countryname,
               WRAP_OUTER_TABLE.code
          FROM ((SELECT countryname, countrycode code
                   FROM country
                  WHERE id > 170) UNION ALL
                (SELECT countryname, countrycode code
                   FROM country
                  WHERE id < 10)) AS WRAP_OUTER_TABLE) AS PAGE_TABLE_ALIAS
 WHERE PAGE_ROW_NUMBER > 1
 ORDER BY PAGE_ROW_NUMBER

第二个,简单查询

@Test
public void testSqlDistinct() throws JSQLParserException {
    String originalSql = "select distinct countrycode,countryname from country order by countrycode";
    System.out.println(sqlServer.convertToPageSql(originalSql, 1, 10));
}

生成的SQL如下(经过人工格式化):

SELECT TOP 10 PAGE_TABLE_ALIAS.countrycode, PAGE_TABLE_ALIAS.countryname
  FROM (SELECT DISTINCT ROW_NUMBER() OVER(ORDER BY countrycode) PAGE_ROW_NUMBER,
                        countrycode,
                        countryname
          FROM country) AS PAGE_TABLE_ALIAS
 WHERE PAGE_ROW_NUMBER > 1
 ORDER BY PAGE_ROW_NUMBER

注意:

1.由于需要提取order by,所以尽可能保证最外层的SQL包含order by

2.如果没有order by,那么上面调用的convertToPageSql还有第四个参数orderBy

public String convertToPageSql(String sql, int offset, int limit, String orderBy) 

如果原来的sql有order by,那么通过该方法指定orderBy之后会覆盖原sql中的order by

人为指定的时候很难把握字段名字的写法,所以建议在sql中带上order by

时间: 2024-10-17 03:44:21

智能将SqlServer的查询语句转换为分页语句的相关文章

一句话,将Linq语句转换为Sql语句

 public IEnumerable<VMB_Report> ReportView_List(VMB_ReportConditions requiredModel) { IEnumerable<VMB_Report> resultModel = new List<VMB_Report>(); IQueryable<Merchant> merchantList; merchantList = Report_List(); #region 从Merchan

Sqlserver的SQL语句实现分页查询

在应用程序的开发中,如果数据库中的数据量过于的庞大,则需要针对查询数据做分页处理,取出对应分页中的数据,在Sqlserver分页的语句写法中,有两种比较常用,一种是数据表中含有自增量Id的情况,可以根据Id的大小顺序进行分页,另一种是数据库中不存在Int类型的Id的情况,此时就需要通过Row_Number函数来实现分页. (1)数据表中存在自增量Id的情况 假设我们查询的表名称为Student,包含的字段有:Id(Id号,自增变量).Name(姓名).BirthDay(出生日期).按出生日期从早

oracle,mysql,SqlServer三种数据库的分页查询

MySql: MySQL数据库实现分页比较简单,提供了 LIMIT函数.一般只需要直接写到sql语句后面就行了.LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如果给出两个参数, 第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数.例如:select * from table WHERE … LIMIT 10; #返回前10行select * from table WHERE … LIMIT 0,10; #返回前

oracle,mysql,SqlServer三种数据库的分页查询总结

MySql: MySQL数据库实现分页比较简单,提供了 LIMIT函数.一般只需要直接写到sql语句后面就行了. LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如果给出两个参数, 第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数.例如: select * from table    LIMIT 10;    #返回前10行 select * from table    LIMIT 0,10; #返回前10行

SqlServer 一个查询语句以致tempdb增大55G (转载)

SqlServer 一个查询语句导致tempdb增大55G 今天操作着服务器,突然右下角提示“C盘空间不足”! 吓一跳!~ 看看C盘,还有7M!!!这么大的C盘空间怎么会没了呢?搞不好等下服务器会动不了! 第一反应就想可能是日志问题,很可能是数据库日志问题 于是查看日志,都不大,正常. dbcc sqlperf(logspace) 看看系统报错: 是tempdb问题,但是刚才看日志才几M,根据提示查看日志状态: select name,log_reuse_wait_desc from sys.d

个人永久性免费-Excel催化剂功能第21波-Excel与Sqlserver零门槛交互-执行SQL语句篇

在前两波中,已完成了Excel与Sqlserver的查询和上传功能,但难免许多临时的或更深入地操作数据库需要用Sql语句来操作,对一般用户电脑里,不可能有条件轻易安装一个数据库客户端软件,就算安装了对其中烦多的功能操作也不胜任. 开发一个简单的接受SQL语句对数据库进行访问操作就有点必要,当然这个落脚点放到Excel上是很不错的选择,毕竟所有用户电脑都有安装Excel. 并且在Excel上批量构造SQL语句也是容易的事,若有数据需要从数据库中导出,Excel作为装载小量数据并进行后续分析的容器是

分页语句-取出sql表中第31到40的记录(以自动增长ID为主键)

sql server方案1: select top 10 * from t where id not in (select top 30 id from t order by id ) orde by id sql server方案2: select top 10 * from t where id in (select top 40 id from t order by id) order by id desc mysql方案:select * from t order by id limit

Mybatis里SQL语句的分页

SQL语句中的分页. 首先在接口中定义,定义的时候是需要通过@Param注解来表示向mybatis里传入参数: public interface GoodsInfoMapper extends IDaoHotel<GoodsInfo> { //定义一个方法,这个方法来表示分页的 List<GoodsInfo> getlistbypage(@Param("startindex")Integer startindex, @Param("endindex&q

20151016学习内容:触发器;分页语句;事务

20151016: --触发器:一种特殊的存储过程,通过对数据库表操作的 --动作,来触发,增删改 alter trigger Fruit_Insert_After --修改用alter on fruit --对哪个表操作的时候执行触发器 instead of insert -- for --(update,delete) for的意思是动作之后触发after等同 as select *from inserted --inserted临时表,就是增加的数据 go select *from stu