前两篇博客:
SQL LIKE语句多条件贪婪匹配算法
SQL LIKE语句多条件贪婪加权匹配算法(改进版)
为了更好的扩充本算法的适用范围,特加入必要关键词指定功能。
在实际应用中,很可能希望匹配的时候必须出现某个词,否则就是没有意义的匹配。
说到这,读者可能觉得这些需求小题大做,在程序中用正则表达式很容易实现,再次重申,现在的矛盾是我们不能把记录返回到程序中处理,因为涉及到大数据量,必须考虑服务器承受能力、并发访问数量、网络传输能力、程序处理能力等诸多因素。在服务器端尽量缩小数据范围,减少数据传输量,无疑是最佳选择。
这个版本加入的新特性即必要关键词指定,同样拿“如何在CSDN网站注册用户”这句话来说,“CSDN”这个词可以认为是必要词,因为它是前提,试想你在搜索“如何在CSDN网站注册用户”时,却出现了“如何在网易注册用户”,显然是毫无意义的结果。
事实亦如此,地球人也是这么做的,在百度搜“如何在CSDN网站注册用户”,把结果从第一页翻到最后一页,可以发现每一个结果中都可以找到“CSDN”字眼。
其实,大多数情况下,通过贪婪加权匹配,已经可以实现非常重要的词“必然”出现,但有时候需要做一个保证,让结果更加合理。
SQLLIKE语句多条件贪婪加权匹配(新增必要词功能):
GO CREATE function Get_StrArrayLength ( @str varchar(1024), --要分割的字符串 @split varchar(10) --分隔符号 ) returns int as begin declare @location int declare @start int declare @length int set @str=ltrim(rtrim(@str)) set @location=charindex(@split,@str) set @length=1 while @location<>0 begin set @start=@location+1 set @location=charindex(@split,@str,@start) set @length=@length+1 end return @length end GO CREATE function Get_StrArrayStrOfIndex ( @str varchar(1024), --要分割的字符串 @split varchar(10), --分隔符号 @index int --取第几个元素 ) returns varchar(1024) as begin declare @location int declare @start int declare @next int declare @seed int set @str=ltrim(rtrim(@str)) set @start=1 set @next=1 set @seed=len(@split) set @location=charindex(@split,@str) while @location<>0 and @index>@next begin set @start=@location+@seed set @location=charindex(@split,@str,@start) set @next=@next+1 end if @location =0 select @location =len(@str)+1 --这儿存在两种情况:1、字符串不存在分隔符号 2、字符串中存在分隔符号,跳出while循环后,@location为0,那默认为字符串后边有一个分隔符号。 return substring(@str,@start,@location-@start) end GO CREATE PROCEDURE proc_Common_SuperLike --要查询的表的主键字段名称 @primaryKeyName varchar(999), --要查询的表名 @talbeName varchar(999), --要查询的表的字段名称,即内容所在的字段 @contentFieldName varchar(999), --查询记录的个数(TOP *),匹配的个数越多,排名越靠前 @selectNumber varchar(999), --匹配字符分隔标记 @splitString varchar(999), --匹配字符组合字符串 @words varchar(999) AS declare @sqlFirst varchar(999) declare @sqlCenter varchar(999) declare @sqlLast varchar(999) declare @next int declare @arrayLength int declare @newWords varchar(999) declare @newTable varchar(999) BEGIN set @newTable=@talbeName set @newWords=@words set @next=dbo.Get_StrArrayLength(@words,'[') --判断是否有必要词 if @next>1 begin set @newTable='' --构造必要表sql语句 while @next>1 begin set @newTable=@newTable+@contentFieldName+' like ''%'+dbo.Get_StrArrayStrOfIndex(dbo.Get_StrArrayStrOfIndex(@words,'[',@next),']',1)+'%'' AND ' set @next=@next-1 end set @newTable=left(@newTable,(len(@newTable)-4)) --构造临时表 set @newTable='SELECT * into ##tempTable FROM '+ @talbeName + ' WHERE ' + @newTable execute(@newTable) --指定临时表 set @newTable='##tempTable' --去掉关键词组中的必要词标记 set @newWords=REPLACE(REPLACE(@words,'[',''),']','') end set @sqlCenter='' set @next=1 set @arrayLength=dbo.Get_StrArrayLength(@newWords,@splitString) while @next<=@arrayLength begin --构造sql查询条件(中间部分) set @sqlCenter = @sqlCenter+'SELECT '+@primaryKeyName+','+CONVERT(varchar(999),@arrayLength-@next+1)+' AS wordPower FROM '+@newTable+' WHERE '+@contentFieldName+' like ''%'+dbo.Get_StrArrayStrOfIndex(@newWords,@splitString,@next)+'%'' UNION ALL ' set @next=@next+1 end --处理sql语句中间部分,去除最后无用语句 set @sqlCenter=left(@sqlCenter,(len(@sqlCenter)-10)) --构造sql语句开头部分 set @sqlFirst='SELECT TOP '+@selectNumber+' '+@primaryKeyName+',COUNT(*)+SUM(wordPower) AS finalPower FROM (' --构造sql语句结尾部分 set @sqlLast=') AS t_Temp GROUP BY '+@primaryKeyName+' ORDER BY finalPower DESC' --拼接出完整sql语句,并执行 Execute(@sqlFirst+@sqlCenter+@sqlLast) --判断临时表是否存在,存在则删除,一定要删除! if OBJECT_ID('tempDb..##tempTable') is not null begin drop table ##tempTable end END
调用方法基本不变(参数个数未变):
execute proc_Common_SuperLike'id','t_test','content','20','|','[i]|o|c'
新特性说明:
l 定义:把必须要出现的关键词用方括号[]括起来。例如[i]|o|c,则i在结果中必须出现。
l 说明:假如需要匹配a、b、c三个关键词,重要性:a>b>c,那么可以这样写:a|b|c,这样已经保证a、b、c的权重依次降低,贪婪加权的算法基本可以保证:尽可能多的去匹配、尽可能匹配包含a的记录。但是某些时候为了提高准确性,要求结果中必须出现a,那么可以这样写:[a]|b|c。同理,必须出现a、b可以这样写:[a]|[b]|c。
l 其他:此次更新加入了临时表技术,保证必要关键词指定效率。