如何剔掉 sql 语句中的尾巴,我用 C# 苦思了五种办法
一:背景
1. 讲故事
这几天都在修复bug真的太忙了,期间也遇到了一个挺有趣bug,和大家分享一下,这是一块sql挺复杂的报表相关业务,不知道哪一位大佬在错综复杂的 嵌套 + 平行 if判断中sql拼接在某些UI组合下出问题了,最终的 sql 架构类似这样的。
var sql = "select 1 union all select 2 union all select 3 union all";
这种sql到数据库去肯定是报错的,有些朋友可能想说这还不简单,在相关的 if 判断中不要追加这个 union all 就好了,这确实是一个根治的办法,但现实情况这一块的业务太复杂了,也不太敢改里面的代码,改的没问题还好,改出问题你得兜着走,所以最保险的办法就是怎么去掉 union all 这个大尾巴,所以我干脆思考了一会,想出了如下五种办法。
二:剔除 union all 的五大方式
1. 最原始的 for 循环
最简单的办法就是通过 for 循环搞定,我可以倒序判断最后几个字符是不是关键词 union all 就可以了,如下代码所示:
static void Main(string[] args)
{
var sql = "select 1 union all select 2 union all select 3 union all";
var keyword = "union all";
var isall = true;
int i = 0;
for (i = 1; i <= keyword.Length; i++)
{
if (keyword[keyword.Length - i] != sql[sql.Length - i])
{
isall = false;
break;
}
}
if (isall)
{
var query = sql.Substring(0, sql.Length - i + 1);
Console.WriteLine(query);
}
}

从代码中可以看出,只要在倒序的过程中,有一个字符和 keyword 中的不符,那就直接跳出,否则就是全匹配,拿到最后的 i 进行 Substring 截取即可。
2. 使用 Substring 搞定
第一种方式确实可以实现,但实现的并不轻松,毕竟大家都是用 C# 写代码而不是 C,为了这点小功能写了这么多代码,显得太 low 了,所以尽量能用类库的方法就用类库的方法吧,改进措施很简单,可以从 sql 尾部切出 keyword.length 个字符,也就是: start:sql.length - keyword.length,然后判断一下是否和 keyword 相等即可,代码修改如下:
static void Main(string[] args)
{
var sql = "select 1 union all select 2 union all select 3 union all";
var keyword = "union all";
var isSucc = sql.Substring(sql.Length - keyword.Length) == keyword;
if (isSucc)
{
var query = sql.Substring(0, sql.Length - keyword.Length);
Console.WriteLine(query);
}
}

3. 使用 LastIndexOf
第二种方式写出来的代码确实比较简洁,但大家有没有发现一个问题,我为了获取最后的 string 做了两次 substring 操作,也就是说在托管堆中生成了两个 string 对象,那能不能免掉一个 substring 呢?给 gc 减轻一些负担,这就可以用到 LastIndexOf 方法了,代码如下:
static void Main(string[] args)
{
var sql = "select 1 union all select 2 union all select 3 union all";
var keyword = "union all";
var index = sql.LastIndexOf(keyword);
if (sql.Length - index == keyword.Length)
{
var query = sql.Substring(0, index);
Console.WriteLine(query);
}
}

思想很简单,就是判断最后出现的 union all的位置到尾部的距离 是否恰好和 keyword.length 一致,如果是的话那 keyword 就是 sql 的大尾巴,这里的 if 写的有点难懂,其实还可以使用 EndsWith 再优化一下代码:
static void Main(string[] args)
{
var sql = "select 1 union all select 2 union all select 3 union all";
var keyword = "union all";
if (sql.EndsWith(keyword))
{
var query = sql.Substring(0, sql.Length - keyword.Length);
Console.WriteLine(query);
}
}

4. 使用 Split 切割
前面几种方式都是在 string 上做文章,要么 substring,要么 LastIndexOf,要么 EndsWith,其实也可以跳出这个定势思维,转换成数组进行处理,用 union all 作为分隔符切割字符串,如果数组的最后一个元素为 string.Empty,那就表明 sql 尾巴就是 keyword, 对吧,代码修改如下:
static void Main(string[] args)
{
var sql = "select 1 union all select 2 union all select 3 union all";
var keyword = "union all";
var arr = sql.Split("union all");
if (string.IsNullOrEmpty(arr[arr.Length - 1]))
{
var query = string.Join(keyword, arr.Take(arr.Length - 1));
Console.WriteLine(query);
}
}

5. 使用 TrimEnd
相信很多朋友用这个方法的场景大多在于剔除尾部的空格,哈哈,其实它还有一个隐藏功能,不仅可以剔除空格,还可以剔除任意多个指定的字符,这就
如何剔掉 sql 语句中的尾巴,我用 C# 苦思了五种办法的更多相关文章
- SQL语句中的单引号处理以及模糊查询
为了防止程序SQL语句错误以及SQL注入,单引号必须经过处理.有2种办法: 1.使用参数,比如SELECT * FROM yourTable WHERE name = @name; 在C#中使用Sql ...
- MyBatis 动态 SQL 语句中出现 '<' 的问题
问题描述 映射接口方法如下: /** * 根据姓名和年龄查询用户信息 * @param name 姓名 * @param user 获取年龄 * @return */ public List<U ...
- sql语句中----删除表数据drop、truncate和delete的用法
sql语句中----删除表数据drop.truncate和delete的用法 --drop drop table tb --tb表示数据表的名字,下同 删除内容和定义,释放空间.简单来说就是把整 ...
- sql语句中获取datetime的日期部分或时间部分
sql语句中获取datetime的日期部分 sql语句中 经常操作操作datetime类型数据.今天在写一个存储过程的时候需要将 一个datetime的值的 日期部分提取出来.网上有许多这方面的介绍. ...
- 解析sql语句中left_join、inner_join中的on与where的区别
以下是对在sql语句中left_join.inner_join中的on与where的区别进行了详细的分析介绍,需要的朋友可以参考下 table a(id, type):id type ---- ...
- SQL语句中count(1)count(*)count(字段)用法的区别
SQL语句中count(1)count(*)count(字段)用法的区别 在SQL语句中count函数是最常用的函数之一,count函数是用来统计表中记录数的一个函数, 一. count(1)和cou ...
- MyBatis Sql语句中的转义字符
1.在xml的sql语句中,不能直接用大于号.小于号要用转义字符 如果用小于号会报错误如下: org.apache.ibatis.builder.BuilderException: Error cre ...
- 在sql语句中添加php变量
在sql语句中使用{}将php变量扩起来,php就会解析{}中的内容. //案件统计 function getCount($dsql,$tableName,$year){ //诉讼案件总数,总金额 $ ...
- 转>>在同一个sql语句中如何写不同条件的count数量
今天在做Portal中的Dashboard展现的时候,需要对多个统计字段做展现,根据我现在的掌握水平,我只能在sql调用构建器中实现一种sql语 句返回的resultSet做展现.没有办法,只能从数据 ...
随机推荐
- js获取页面高度
<script> function getInfo() { var s = ""; s += " 网页可见区域宽:"+ document.body. ...
- ThreeJS学习6_几何体相关(BufferGeometry)
ThreeJS学习6_几何体相关(BufferGeometry) 使用 BufferGeometry 可以有效减少向 GPU 传输几何体相关数据所需的开销 可以自定义顶点位置, 面片索引, 法向量, ...
- Github上的沙雕项目,玩100遍都不够
这段时间大家在家自我隔离.居家办公憋坏了吧.为了打发这种无聊的生活,我决定拿出我在github上珍藏多年的沙雕项目,让大家在无聊的时候可以打发时间. Github作为互联网上最大的开源社区,一直备受程 ...
- Codeforces Round 662 赛后解题报告(A-E2)
Codeforces Round 662 赛后解题报告 梦幻开局到1400+的悲惨故事 A. Rainbow Dash, Fluttershy and Chess Coloring 这个题很简单,我们 ...
- django—路由相关
django不同版本的路由配置 django 2之前,配置urlpatterns使用的是url方法 django 2之后,配置urlpatterns使用的是path方法 path与url的区别: ur ...
- Spring之IOC/DI(反转控制/依赖注入)_入门Demo
在平时的java应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,在没有使用Spring的时候,每个对象在需要使用他的合作对象时,自己均要使用像new ob ...
- windows18.04远程桌面连接ubuntu16.04
方法1: https://www.cnblogs.com/xuliangxing/p/7642650.html 方法2: 也可以通过在ubuntu上安装samba.
- MySql与Oracle的几个主要区别
转自:https://blog.csdn.net/c332472988/article/details/52804078 一.并发性 并发性是oltp数据库最重要的特性,但并发涉及到资源的获取.共享与 ...
- B. Game of the Rows 解析(思維)
Codeforce 839 B. Game of the Rows 解析(思維) 今天我們來看看CF839B 題目連結 題目 有如下圖片所示的飛機座位\(n\)排,和\(k\)隊士兵,每隊數量不一定. ...
- 一起学Vue:路由(vue-router)
前言 学习vue-router就要先了解路由是什么?前端路由的实现原理?vue-router如何使用?等等这些问题,就是本篇要探讨的主要问题. vue-router是什么 路由是什么? 大概有两种说法 ...