在SQL Server中经常会用到模糊匹配字符串的情况,最简单的办法就是使用like关键字(like语法http://msdn.microsoft.com/en-us/library/ms179859.aspx)。但是如果我们使用的前后都加%的方式,是没办法用到索引进行快速查询的,所以很多情况下我们使用左匹配的方式。最常见的一个例子就是在搜索框中,用户输入了一部分关键字,系统可以通过用户的输入进行左匹配,找出相关的结果列出来。使用左匹配的好处是可以使用到SQL Server中对该字段建立的索引,使得查询效率很高,但是不好的SQL语句仍然会导致索引无法使用。

假设我们现在有个表YCMRSALE,其中有个字段MATNR存储了料号信息,如果我们要从这个表中查询出以AB开头的料号,如果使用NHibernate,那么我们常用的写法有:

//QueryOver的写法
var result = session.QueryOver<Ycmrsale>().WhereRestrictionOn(c => c.Matnr).IsLike("AB", MatchMode.Start).List<Ycmrsale>();
//Linq to NHibernate
result = session.Query<Ycmrsale>().Where(c => c.Matnr.StartsWith("AB")).ToList();
//Criteria写法
result = session.CreateCriteria<Ycmrsale>().Add(Expression.Like("Matnr", "AB", MatchMode.Start)).List<Ycmrsale>();

这几种写法本质上都是生成了如下的where条件语句:

where ycmrsale0_.Matnr like 'AB%'

如果使用EntityFramework,那么查询的C#代码也和NHibernate类似:

var result = bwEntities.YCMRSALEs.Select(s => s.MATNR).Where(s => s.StartsWith("AB"));

where条件也是一样的:

WHERE [Extent1].[MATNR] LIKE 'AB%'

这里只是举了最简单的情况,如果我们要查询的料号本身就包含%,比如要查询以”%00”开头的料号,那么怎么保证这里的%是百分号而不是表示模糊匹配的意思呢?

使用EntityFramework就很简单,什么都不需要修改,系统会根据传入的字符串生成不同的SQL语句:

var result = bwEntities.YCMRSALEs.Select(s => s.MATNR).Where(s => s.StartsWith("%00"));

生成的SQL Where条件:

WHERE [Extent1].[MATNR] LIKE '~%00%' ESCAPE '~'

对开发人员来说,真是很简单,什么输入都不用管。但是如果用NHibernate就要麻烦点了,我们必须要判断用户输入的字符串里面是否有特殊转移符,如果有,那么就需要进行替换,而且C#查询语句也有所不同。

string input = "%00";
Regex regex=new Regex(@"[~%\[\]_]");
input= regex.Replace(input, delegate(Match m) { return "~" + m.Value; });
var result = session.QueryOver<Ycmrsale>().WhereRestrictionOn(c => c.Matnr).IsLike(input, MatchMode.Start,'~').List<Ycmrsale>();
生成的SQL Where条件:
WHERE this_.Matnr like @p0 escape '~';@p0 = '~%00%'

以上说的都是在ORMapping的工具中进行左匹配查询,如果我们要在SQL语句中直接进行查询还有一种写法就是用left函数。同样以YCMRSALE表举例,如果我们有另一表matnr,该表中的matnr列存储了不完整的料号,现在需要将两个表join起来,使用matnr列进行左匹配,那么我们的SQL可以写成:

select *
from YCMRSALE s
inner join matnr m
on left(s.MATNR,len(m.matnr))=m.matnr

这个写法能够得到我们想要的结果,但是由于对MATNR列使用了函数,所以无法使用索引,所以查询速度很慢。

如果我们要改写成like的形式,那么就需要对matnr表中的matnr列进行处理,将特殊字符进行替换,将~%_[]这几个字符都替换掉。所以我们的SQL查询就会变成这样:

select *
from YCMRSALE s
inner join matnr m
on s.MATNR like replace(replace(replace(replace( replace(m.matnr,'~','~~'),'_','~_'),'[','~['),']','~]'),'%','~%')+'%' escape '~'

这里的SQL虽然看起来比较Ugly,但是却可以用上YCMRSALE表上对MATNR建立的索引,所以效率较高。

除了ESCAPE这个关键字的处理方式外,微软官方还给出了另一种解决办法,那就是使用“[]”将转义字符括起来。这种写法比escape关键字的写法要简单点,对应的SQL为:

select *
from YCMRSALE s
inner join matnr m
on s.MATNR like replace(replace(replace( m.matnr,'[','[[]'),'_','[_]'),'%','[%]')+'%'

甚至我们还可以先写个自定义函数对转移字符进行处理对于join的情况,那就非常复杂了。。。

create function OpStr(@input varchar(50))
returns varchar(100)
as
begin
declare @i int=1;
declare @result varchar(100)='';
declare @c char(1)
while(@i<=len(@input))
begin
set @c=substring(@input,@i,1);
if (@c='[' or @c='%' or @c='_')
begin
set @result+='['+@c+']';
end
else
begin
set @result+=@c;
end
set @i+=1;
end
return @result
end
然后在查询中调用这个自定义的函数即可。

select *
from YCMRSALE s
inner join matnr m
on s.MATNR like dbo.OpStr(m.matnr)+'%'

SQL Server字符串左匹配的更多相关文章

  1. sql server 字符串替换函数REPLACE

    sql server 字符串替换函数REPLACE函数的使用 <pre name="code" class="sql">--参数1:需要替换字符的母 ...

  2. sql server字符串的类型

    sql server字符串分为不同的类型,下面就将为您介绍几个sql server字符串的常见类型,希望对您学习sql server字符串能有所帮助. nchar 此数据类型可存储1~4000个定长U ...

  3. sql server 字符串转成日期格式

    在SQL Server数据库中,SQL Server日期时间格式转换字符串可以改变SQL Server日期和时间的格式,是每个SQL数据库用户都应该掌握的.本文我们主要就介绍一下SQL Server日 ...

  4. [转]SQL Server字符串处理函数大全

    select语句中只能使用sql函数对字段进行操作(链接sql server), select 字段1 from 表1 where 字段1.IndexOf("云")=1;这条语句不 ...

  5. SQL SERVER字符串函数

    本篇文章还是学习<程序员的SQL金典>内容的记录,此次将讲解的是SQL SERVER的字符串函数. 其实数据库跟程序语言库一样,都会集成很多可以使用的API.这些API,如果你熟悉的话,将 ...

  6. Sql Server 字符串操作总结

    SQL Server 支持两种字符数据类型---常规和Unicode:常规类型包括char 和varchar:unicode包括nchar 和nvarchar.常规的每个字符占用一个字节存储,而uni ...

  7. SQL Server ->> 字符串对比

    今天同事问我关于SQL Server在字符串尾随着空格时进行字符串对比的做法.关于这个问题正好在这里讲一下,就是SQL Server是按照ANSI/ISO SQL-92中的定义做字符串对比的. 在KB ...

  8. sql server 字符串函数大全

    平常会用到一些函数处理字符串,用的不算频繁,所以每次用到的时候就忘记了,这次在网上找了一篇文档,担心突然某一天这篇文章找不到了,然后就把文章的内容复制了一份: /* 1,ASCII返回字符表达式中最左 ...

  9. SQL SERVER 字符串函数 STRING_SPLIT()

    定义: STRING_SPLIT()函数根据指定的分隔符将字符串拆分为子字符串行. ※STRING_SPLIT 要求兼容性级别至少为 130. (即SSMS 2016及以上版本) ※级别低于 130 ...

随机推荐

  1. LeetCode124:Binary Tree Maximum Path Sum

    题目: Given a binary tree, find the maximum path sum. The path may start and end at any node in the tr ...

  2. 鼠标向下滑动加载div

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. 去除utf8文件的bom标记

    http://stackoverflow.com/questions/1068650/using-awk-to-remove-the-byte-order-mark http://thegreyblo ...

  4. Intellij Idea上传本地项目到Git

    方法一:选择菜单VCS-Import into Version Control - Share project on Github,填写仓库名和github账户之后,点击"Share&quo ...

  5. 第十一届“蓝狐网络杯”湖南省大学生计算机程序设计竞赛 B - 大还是小? 字符串水题

    B - 大还是小? Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format: Description 输入两个实数,判断第一个数大 ...

  6. iOS 10 常见配置的问题

    UITextField 在iOS 10 中,UITextField新增了textContentType字段,是UITextContentType类型,它是一个枚举,作用是可以指定输入框的类型,以便系统 ...

  7. CGI与Servlet的比较

    转自:http://www.maxhis.info/java/cgi-vs-servlet/ 谢! 概括来说,CGI和Servlet可以完成相同的功能. 一:CGI(Common Gateway In ...

  8. 2016读书List

    2016年读书书单. 1. <华尔街漫步> + <战胜华尔街>+ <华尔街之狼> 2. <野蛮大陆> 3. <第三帝国的最后十四天> 4. ...

  9. Java经典实例:进阶版堆栈实现,支持任何对象类型

    支持任何对象类型,有更多的错误检查. package Stack; /** * Created by Frank */ public class MyStack<T> implements ...

  10. 设计模式之 面向对象的养猪厂的故事,C#演示(二)

    (三) 优先使用聚合,而不是继承 有一段时间,养猪场的老板雇用了清洁工人来打扫猪舍.但有一天,老板忽然对自己说"不对啊,既然我有机器人,为什么还要雇人来做这件事情?应该让机器人来打扫宿舍!& ...