Skip to content

Commit

Permalink
Merge pull request #44 from hoperunChen/tbs/TV360X-2551
Browse files Browse the repository at this point in the history
for TV360X-2551 添加在sql语句最外层添加OrderBy字段
  • Loading branch information
zhangdaiscott authored Sep 27, 2024
2 parents f6d02e0 + 6714345 commit a4efe73
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 11 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
MiniDao
=======
当前最新版本: 1.10.1 (发布日期:2024-07-03
当前最新版本: 1.10.2 (发布日期:2024-09-27

[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
[![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://jeecg.com/aboutusIndex)
[![](https://img.shields.io/badge/Blog-官方博客-blue.svg)](https://jeecg.blog.csdn.net)
[![](https://img.shields.io/badge/version-1.10.1-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
[![](https://img.shields.io/badge/version-1.10.2-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)

Expand Down Expand Up @@ -44,7 +44,7 @@ MiniDao 是一款轻量级JAVA持久层框架,基于 SpringJdbc + freemarker
<dependency>
<groupId>org.jeecgframework</groupId>
<artifactId>minidao-pe</artifactId>
<version>1.10.1</version>
<version>1.10.2</version>
</dependency>
```

Expand Down
15 changes: 14 additions & 1 deletion docs/修改日志.log
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,17 @@ org/jeecgframework/minidao/sqlparser/impl/SimpleSqlProcessor.java(+)
org/jeecgframework/minidao/sqlparser/AbstractSqlProcessor.java(+)
org/jeecgframework/minidao/util/MiniDaoUtil.java
org/jeecgframework/minidao/util/ReflectUtil.java
---author:scott---date:2024-07-04-----for:SQL解析兼容机制(判断支持JSqlParser,才用JSqlParser引擎)---
---author:scott---date:2024-07-04-----for:SQL解析兼容机制(判断支持JSqlParser,才用JSqlParser引擎)---

---author:chenrui---date:2024/9/27-----for:[TV360X-2551]添加在sql语句最外层添加OrderBy字段---
pom.xml
README.md
minidao-pe/src/main/java/org/jeecgframework/minidao/sqlparser/impl/JsqlparserSqlProcessor.java
minidao-pe/src/main/java/org/jeecgframework/minidao/sqlparser/impl/SimpleSqlProcessor.java
minidao-pe/src/main/java/org/jeecgframework/minidao/sqlparser/AbstractSqlProcessor.java
minidao-pe/src/main/java/org/jeecgframework/minidao/util/MiniDaoUtil.java
minidao-pe/pom.xml
minidao-pe-example/src/test/java/test/SqlParserTest.java (+)
minidao-pe-example/pom.xml
minidao-spring-boot-starter/pom.xml
---author:chenrui---date:2024/9/27-----for:[TV360X-2551]添加在sql语句最外层添加OrderBy字段---
13 changes: 10 additions & 3 deletions minidao-pe-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.jeecgframework</groupId>
<artifactId>minidao-pe-example</artifactId>
<version>1.10.1</version>
<version>1.10.2</version>
<packaging>jar</packaging>
<url>http://www.jeecg.com</url>
<parent>
<groupId>org.jeecgframework</groupId>
<artifactId>minidao-parent</artifactId>
<version>1.10.1</version>
<version>1.10.2</version>
</parent>

<properties>
<minidao.version>1.10.1</minidao.version>
<minidao.version>1.10.2</minidao.version>
<junit.version>4.13.1</junit.version>
<springframework.version>5.3.31</springframework.version>
<!-- 数据库驱动 -->
Expand Down Expand Up @@ -48,6 +48,13 @@
</repositories>

<dependencies>
<!-- jsqlparser,只在测试时使用 -->
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
Expand Down
128 changes: 128 additions & 0 deletions minidao-pe-example/src/test/java/test/SqlParserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package test;

import org.jeecgframework.minidao.sqlparser.impl.JsqlparserSqlProcessor;
import org.jeecgframework.minidao.sqlparser.impl.SimpleSqlProcessor;
import org.jeecgframework.minidao.util.MiniDaoUtil;
import org.junit.Test;

/**
* @Description: sql解析单元测试
* @Author: chenrui
* @Date: 2024/9/27 15:46
*/
public class SqlParserTest {

/**
* 测试miniDaoUtil:添加order by
* @author chenrui
* @date 2024/9/27 19:14
*/
@Test
public void testAddOrderMiniUtil() {
// 复杂嵌套语句
String sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name ORDER BY theme_name2 Desc,theme_name1,theme_name;";
System.out.println("before:" + sql);
String result1 = MiniDaoUtil.addOrderBy(sql, "base_theme_name", true);
System.out.println("after:" + result1);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name;";
result1 = MiniDaoUtil.addOrderBy(sql, "base_theme_name", true);
// 普通语句
System.out.println("after1:" + result1);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM ABC order By theme_name DESC";
System.out.println("before2:" + sql);
result1 = MiniDaoUtil.addOrderBy(sql, "base_theme_name", true);
System.out.println("after2:" + result1);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM ABC";
System.out.println("before3:" + sql);
result1 = MiniDaoUtil.addOrderBy(sql, "base_theme_name", true);
System.out.println("after3:" + result1);
}


/**
* 测试jsqlParser的添加排序功能
* @author chenrui
* @date 2024/9/27 19:14
*/
@Test
public void testAddOrderJSqlParser() {
JsqlparserSqlProcessor processor = new JsqlparserSqlProcessor();
String sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name ORDER BY theme_name2 Desc,theme_name1,theme_name;";
System.out.println("before:" + sql);
String newSql = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after:" + newSql);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name;";
System.out.println("before1:" + sql);
newSql = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after1:" + newSql);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name ORDER BY base_theme_name Desc;";
System.out.println("before2:" + sql);
newSql = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after2:" + newSql);
}

/**
* 测试简单解析器的添加排序功能
* @author chenrui
* @date 2024/9/27 19:14
*/
@Test
public void testAddOrderSimpleParser() {
SimpleSqlProcessor processor = new SimpleSqlProcessor();
// 复杂嵌套语句
String sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name ORDER BY theme_name2 Desc,theme_name1,theme_name;";
System.out.println("before:" + sql);
String result1 = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after:" + result1);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name;";
result1 = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after1:" + result1);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM (" +
"SELECT x.theme_name,(" +
"SELECT theme_name FROM (" +
"SELECT e.theme_name FROM BASE_INFO e WHERE e.THEME_CODE='3' ORDER BY e.VERSION*1 DESC) WHERE ROWNUM=1) AS base_theme_name FROM BUSINESS_INDEX x WHERE 1=1) " +
"GROUP BY theme_name,base_theme_name ORDER BY base_theme_name Desc;";
System.out.println("before2:" + sql);
result1 = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after2:" + result1);
// 普通语句
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM ABC order By theme_name DESC";
System.out.println("before3:" + sql);
result1 = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after3:" + result1);
sql = "SELECT COUNT(*) AS count,theme_name,base_theme_name FROM ABC";
System.out.println("before4:" + sql);
result1 = processor.addOrderBy(sql, "base_theme_name", true);
System.out.println("after4:" + result1);
}


}
2 changes: 1 addition & 1 deletion minidao-pe/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>org.jeecgframework</groupId>
<artifactId>minidao-pe</artifactId>
<version>1.10.1</version>
<version>1.10.2</version>
<packaging>jar</packaging>

<name>minidao-pe</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,17 @@ public interface AbstractSqlProcessor {
* @return
*/
List<Map<String, Object>> parseSqlFields(String parsedSql);


/**
* 在SQL的最外层增加或修改ORDER BY子句
* @for TV360X-2551
* @param sql 原始SQL
* @param field 新的ORDER BY字段
* @param isAsc 是否正序
* @return
* @author chenrui
* @date 2024/9/27 17:25
*/
String addOrderBy(String sql, String field, boolean isAsc);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.parser.SimpleNode;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.*;
import org.jeecgframework.minidao.pojo.MiniDaoPage;
import org.jeecgframework.minidao.sqlparser.AbstractSqlProcessor;
Expand Down Expand Up @@ -98,6 +99,58 @@ public List<Map<String, Object>> parseSqlFields(String parsedSql) {
return list;
}

/**
* 在SQL的最外层增加或修改ORDER BY子句
* @for TV360X-2551
* @param sql 原始SQL
* @param field 新的ORDER BY字段
* @param isAsc 是否正序
* @return
* @author chenrui
* @date 2024/9/27 17:25
*/
@Override
public String addOrderBy(String sql, String field, boolean isAsc) {
Statement statement = null;
try {
statement = CCJSqlParserUtil.parse(sql);
} catch (JSQLParserException e) {
throw new RuntimeException(e);
}

if(statement instanceof Select){
Select selectStatement = (Select) statement;
SelectBody selectBody = selectStatement.getSelectBody();
if (selectBody instanceof PlainSelect) {
PlainSelect plainSelect = (PlainSelect) selectBody;
List<OrderByElement> orderByElements = plainSelect.getOrderByElements();
OrderByElement orderByElement = new OrderByElement();
orderByElement.setExpression(new Column(field)); // 你想要添加的字段
orderByElement.setAsc(isAsc); // 按正序排序
if (orderByElements != null && !orderByElements.isEmpty()) {
// 如果已经有ORDER BY,则添加到现有的ORDER BY中
long existsCount = orderByElements.stream().filter(orderByEl -> {
Expression expression = orderByEl.getExpression();
if (expression instanceof Column) {
Column column = (Column) expression;
return column.getColumnName().equalsIgnoreCase(field);
} else {
return false;
}
}).count();
if (existsCount == 0) {
orderByElements.add(orderByElement);
}
} else {
// 如果没有ORDER BY,则创建一个新的ORDER BY子句
plainSelect.setOrderByElements(Collections.singletonList(orderByElement));
}
sql = plainSelect.toString();
}
}
return sql;
}


private static void getMapFiled(List<Map<String, Object>> list, List<String> tableAndColumns) {
Map<String, Object> map = new HashMap(5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.jeecgframework.minidao.util.MiniDaoUtil;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
Expand Down Expand Up @@ -86,6 +87,86 @@ public List<Map<String, Object>> parseSqlFields(String parsedSql) {
}


/**
* 排序方向
* @for TV360X-2551
*/
private static final List<String> ORDER_DIRECTION = Arrays.asList("ASC", "DESC");

/**
* 在SQL的最外层增加或修改ORDER BY子句
* @for TV360X-2551
* @param sql 原始SQL
* @param field 新的ORDER BY字段
* @param isAsc 是否正序
* @return
* @author chenrui
* @date 2024/9/27 17:25
*/
@Override
public String addOrderBy(String sql, String field, boolean isAsc) {
// 解析SQL以找到最外层的ORDER BY
int orderByIndex = findOuterOrderBy(sql);
field = field.trim().toLowerCase(); // 处理新字段

String orderField = " " + field + " " + (isAsc ? "ASC" : "DESC") + " ";

if (orderByIndex != -1) {
// 找到最外层的ORDER BY
String existingOrderByClause = sql.substring(orderByIndex + 8).trim().toLowerCase(); // 获取ORDER BY之后的字段

// 检查新字段是否已经存在
String replaceReg = "\\s*[,;\\s]\\s*";
String[] existingOrderByFields = existingOrderByClause.split(replaceReg);
for (String existingOrderByField : existingOrderByFields) {
if (null != existingOrderByField
&& !ORDER_DIRECTION.contains(existingOrderByField.trim())) {
if(existingOrderByField.equalsIgnoreCase(field)){
// 新字段已存在,直接返回原SQL
return sql;
}
}
}

// 新字段插入现有ORDER BY之前
return sql.substring(0, orderByIndex + 8) + " " + orderField + ", " + sql.substring(orderByIndex + 8);
} else {
// 如果没有ORDER BY,则在SQL的最后插入ORDER BY
if(sql.trim().endsWith(";")){
sql = sql.substring(0, sql.lastIndexOf(";"));
}
return sql.trim() + " ORDER BY " + orderField;
}
}

/**
* 查找最外层的ORDER BY的索引
*
* @param sql 要解析的SQL字符串
* @return 最外层ORDER BY的索引,如果没有则返回-1
*/
private static int findOuterOrderBy(String sql) {
int nestedLevel = 0; // 记录括号的嵌套层次
int orderByIndex = -1;
String lowerSql = sql.toLowerCase(); // 转换为小写以便不区分大小写

// 遍历SQL字符串,处理括号嵌套情况
for (int i = 0; i < lowerSql.length(); i++) {
char c = lowerSql.charAt(i);
if (c == '(') {
nestedLevel++; // 进入嵌套
} else if (c == ')') {
nestedLevel--; // 退出嵌套
} else if (nestedLevel == 0 && lowerSql.startsWith("order by", i)) {
// 只有在最外层时匹配到ORDER BY
orderByIndex = i;
break;
}
}
return orderByIndex;
}


/**
* @param sql
* @return
Expand Down
Loading

0 comments on commit a4efe73

Please sign in to comment.