前两篇博客:
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 其他:此次更新加入了临时表技术,保证必要关键词指定效率。