原创 SQL语句实现按关健字模糊查询,并按匹配度排序收藏

新一篇: SQL得到一个字串在另一个字串组(以特定字符分隔)中的位置. | 旧一篇: 领导风格. 先放这,没事就看看.

今天有人在CSDN上问,我就随手写了一段.

 CREATE TABLE tb (ID INT IDENTITY(1,1),VALUE VARCHAR(100))
INSERT tb SELECT '中国'
UNION ALL SELECT '中国人'
UNION ALL SELECT '中国人民'
UNION ALL SELECT '日本'
UNION ALL SELECT '日本人'
UNION ALL SELECT '我的心中有人姑娘'
UNION ALL SELECT '人民网'
UNION ALL SELECT '中国是个伟大的国家'
UNION ALL SELECT '我们都是中国人,都是炎黄子孙,都是龙人传人'

DECLARE @searchSTR VARCHAR(20)
SET @searchSTR='中国人'
SELECT ID,VALUE FROM tb a
INNER JOIN fn_SplitStringToROWS(@searchSTR) b
   
ON CHARINDEX(b.v,a.VALUE)>0
   
WHERE VALUE LIKE '%[中国人]%'
   
GROUP BY ID,VALUE
   
ORDER BY COUNT(DISTINCT v) DESC
   
DROP TABLE tb

--附函数
CREATE FUNCTION fn_SplitStringToROWS
(
@str VARCHAR(100)
)
RETURNS @t TABLE(v VARCHAR(2))
AS
BEGIN
   
DECLARE @i INT
   
SET @i=1
   
WHILE @i<=LEN(@str)
       
BEGIN
           
INSERT @t SELECT SUBSTRING(@str,@i,1)
           
SET @i=@i+1
       
END
   
RETURN
END

/*


(所影响的行数为 9 行)

ID          VALUE                                                                                               
----------- ----------------------------------------------------------------------------------------------------
9           我们都是中国人,都是炎黄子孙,都是龙人传人
2           中国人
3           中国人民
8           中国是个伟大的国家
1           中国
6           我的心中有人姑娘
7           人民网
5           日本人

(所影响的行数为 8 行)

*/

如果要实现匹配度排序,那么可以去掉 WHERE ... LIKE那句,多余

如果只想实现模糊的匹配,那么可以不需要连表,直接

SELECT ID,VALUE FROM tb  WHERE VALUE LIKE '%[中国人]%' 即可.

 

 

按词匹配.

create function f_splitIDX(@SourceSql varchar(8000),@StrSeprate varchar(10))
returns @temp table(id int identity(1,1),v varchar(100))

begin
   
declare @i int
   
set @SourceSql=rtrim(ltrim(@SourceSql))
   
set @i=charindex(@StrSeprate,@SourceSql)
   
while @i>=1
   
begin
       
insert @temp values(left(@SourceSql,@i-1))
       
set @SourceSql=substring(@SourceSql,@i+1,len(@SourceSql)-@i)
       
set @i=charindex(@StrSeprate,@SourceSql)
   
end
   
if @SourceSql<>'\'
      
insert @temp values(@SourceSql)
   
return
end


CREATE TABLE tb (ID INT IDENTITY(1,1),VALUE VARCHAR(100))
INSERT tb SELECT '中国'
UNION ALL SELECT '中国人,中国'
UNION ALL SELECT '中国,中国人'
UNION ALL SELECT '中国人民'
UNION ALL SELECT '中国'
UNION ALL SELECT '日本'
UNION ALL SELECT '日本人'
UNION ALL SELECT '我的心中有人姑娘'
UNION ALL SELECT '人民网'
UNION ALL SELECT '中国是个伟大的国家'
UNION ALL SELECT '我们都是中国人,都是炎黄子孙,都是龙人传人'
DECLARE @searchSTR VARCHAR(20)
SET @searchSTR='中国人 中国'

SELECT a.ID,VALUE FROM tb a
   
INNER JOIN dbo.f_splitIDX(@searchSTR,' ') b
   
ON CHARINDEX(v,VALUE)>0
   
GROUP BY a.ID,Value
   
ORDER BY COUNT(DISTINCT v) DESC,MIN(b.id),a.id

DROP TABLE tb

发表于 @ 2007年10月17日 16:24:00|评论(loading...)|编辑

新一篇: SQL得到一个字串在另一个字串组(以特定字符分隔)中的位置. | 旧一篇: 领导风格. 先放这,没事就看看.

评论

#szmuma 发表于2008-06-12 10:30:48  IP: 221.225.55.*
请问我用的是asp编程,要用你的这个功能,是否要在sql数据库里建一个存储过程,然后在asp代码里调用?望解答
#fcuandy 发表于2008-06-12 20:09:26  IP: 125.71.43.*
需要先创建函数。

然后
你可以创建存贮过程,将待查询字串以参数传入。
也可以在asp中以批语句的方式执行比如:

dim strSQL
strSQL="DECLARE @s VARCHAR(100);" &_
"SELECT a...... ;" & _
..
这样来执行。
#szmuma 发表于2008-06-17 15:03:09  IP: 58.209.88.*
CREATE PROCEDURE SP_DOWNLOAD(@KEYWORD VARCHAR(20))
AS
DECLARE @SEARCHSTR VARCHAR(20)
SET @SEARCHSTR=@KEYWORD

CREATE TABLE #T(V VARCHAR(10))
DECLARE @I INT
SET @I=1
BEGIN
WHILE @I<=LEN(@SEARCHSTR)
BEGIN
INSERT INTO #T(V) VALUES(SUBSTRING(@SEARCHSTR,@I,1))
SET @I=@I+1
END
END

SELECT ID,DownName,SortID,AddTime FROM NwebCn_Download a
INNER JOIN #T b
ON CHARINDEX(b.V,a.DownName)>0
GROUP BY ID,DownName,SortID,AddTime
ORDER BY COUNT(DISTINCT V) DESC
DROP TABLE #T
GO

这是上面改造成的存储过程,基本上能查出来按匹的字数排列,但有的关键字行,有的不行
#szmuma 发表于2008-06-17 15:21:43  IP: 58.209.88.*
不知道哪里错了请指正
有的NewsName里关键字多反而排在关键字少的NewsName后面
#fcuandy 发表于2008-06-17 22:45:19  IP: 222.209.128.*
这个是不进行重复匹配的。意思是
有记录

中国人
中国人人
中国人人人
中国

待搜"中国人"
那么前三条记录的匹配度是一样的,对于"人"字,不计重复匹配,前三条记录都匹配了三个字。

你的改写大致是没有问题的。
如果你希望得到的是记录重复匹配那么:将
ORDER BY COUNT(DISTINCT v) DESC
改为

ORDER BY SUM(LEN(value)-LEN(REPLACE(value,v,''))) DESC

即可。

应用到你的环境,那么把value改为DownName即可。
#only_endure 发表于2008-07-24 20:50:34  IP: 222.187.22.*
偶像 :D 您好
您的代码我调试了,为了看得更仔细些,我多加了一列
/*test
SELECT ID,VALUE,b.v FROM tb a
INNER JOIN fn_SplitStringToROWS(@searchSTR) b
ON CHARINDEX(b.v,a.VALUE)>0;
*/
这种情况下,查可以看到结果的:
1,中国,中
2,中国人,中
3,中国人民,中
6,我的心中有人姑娘,中
8,中国是个伟大的国家,中
9,我们都是中国人,都是炎黄子孙,都是龙人传人,中
1,中国,国
2,中国人,国
3,中国人民,国
8,中国是个伟大的国家,国
9,我们都是中国人,都是炎黄子孙,都是龙人传人,国
2,中国人,人
3,中国人民,人
5,日本人,人
6,我的心中有人姑娘,人
7,人民网,人
9,我们都是中国人,都是炎黄子孙,都是龙人传人,人
但是我在整句中调试,
DECLARE @searchSTR VARCHAR(20)
SET @searchSTR='中国人'

SELECT ID,VALUE,b.v FROM tb a
INNER JOIN fn_SplitStringToROWS(@searchSTR) b
on charindex(b.v,a.value)>0
WHERE VALUE LIKE '%[中国人]%'
GROUP BY ID,VALUE
ORDER BY COUNT(DISTINCT v) DESC
则出现错误:
消息 8120,级别 16,状态 1,第 4 行
选择列表中的列 'fn_SplitStringToROWS.v' 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中
#only_endure 发表于2008-07-24 20:52:57  IP: 222.187.22.*
我之所以这么做,是想更加清楚数据集一点一点变化分组排序演变的,但是这样调试失败了,而且我也猜不透最后一句ORDER BY COUNT(DISTINCT v) DESC
怎么得到的最后排序结果,
9 我们都是中国人,都是炎黄子孙,都是龙人传人
2 中国人
3 中国人民
8 中国是个伟大的国家
1 中国
6 我的心中有人姑娘
7 人民网
5 日本人

很是头痛,麻烦您能帮忙解释一下么?不胜感激:)
#fcuandy 发表于2008-07-25 05:32:37  IP: 222.209.137.*
fn_splitstringtorows将列按字符拆分成行,
也即
如果@searchStr='中国人'
那么将被拆为三行
v
----




然后与原表连, 比如原表中 id=9的记录中,有3个'人'字,一个'中',一个'国'字。
如果不去重的话,即 '中国人'中的三个字,在此记录中共出现了5次。 现在去重的话,那么就是3次。
#only_endure 发表于2008-07-25 08:23:04  IP: 222.45.89.*
9 我们都是中国人,都是炎黄子孙,都是龙人传人
2 中国人
3 中国人民
8 中国是个伟大的国家
1 中国
6 我的心中有人姑娘
7 人民网
5 日本人
===
老师,9,2,3应该是并列的,8,1也是并列的,6,7,5是并列的,她们之间是怎么排列的呢?
#wzy_love_sly 发表于2008-07-25 08:41:27  IP: 123.123.115.*
嘿嘿,跑这偷学来了
#only_endure 发表于2008-07-25 08:46:17  IP: 222.45.89.*
:)
发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © 云