sql 数据库可以返回一个 sql 结果集加上结果的分数吗?
Posted
技术标签:
【中文标题】sql 数据库可以返回一个 sql 结果集加上结果的分数吗?【英文标题】:Could a sql database return a sql result set plus a score for the results? 【发布时间】:2011-01-31 23:44:03 【问题描述】:只是好奇,如果我想将字符串发送到数据库(可能是 MS SQL Server),任何人都可以提供有关从数据库返回结果的最佳方法的任何见解,其中结果集可能被排序和“评分” " 与传入的字符串是否接近?
所以,如果我发送查询:
SELECT name FROM table where name LIKE 'Jon'
然后得到 1000 个结果的结果,如下所示:
100 Jon
98 John
80 Jonathan
32 Nathan
视图、索引、存储过程、编码解决方案?有什么建议?
【问题讨论】:
en.wikipedia.org/wiki/Levenshtein_distance 为什么“Nathan”会出现在结果中? @Mitch - 你如何应用它,因为 Levenshtein + LIKE 总是只是 Len(str) - Len(like-expr)... @cyberkiwi:你读过维基页面吗? @Mitch - 如果 2 个字符串类似于 '%JON%',则 JON 已经是两个字符串的一部分,因此 Levenshtein 距离 = 要添加的字符数 = len(A)-len(B ) 对?我确实扫描了 wiki,但什么也没看到 【参考方案1】:你可以,但你需要使用另一个函数来做到这一点。 Levenshtein ratio 或Jaro distance 将是最常见的解决方案。我不确定 SQL Server 包含什么(如果有的话)为此内置的。如果不出意外,我认为您可以使用 here 所述的 SimMetrics 库。无论如何,它看起来像这样。
select top 1000
jaro('John', name) as score, name
from table
where name like '%John%'
order by 1 desc
【讨论】:
对于在这个网站上积分很少的人来说,这是一个很好的答案。谢谢。另外,感谢cyberkiwi。【参考方案2】:编辑
由于来自 cmets 的一些持续刺激,我在这里展示了一个用 SQL 计算 Levenshtein 距离的实现。此处使用 SQL Server 2005+ 的 TSQL,但该技术也可以转换为其他 DBMS。 最高分为 100。
;with tbl as (
select 'Jon' AS Name union all
select 'Jonathan' union all
select 'Jonny' union all
select 'John' union all
select 'Bone' union all
select 'BJon' union all
select 'Nathan' union all
select 'Jonne')
SELECT *, SCORE_Levenshtein + SCORE_SOUNDEX TotalScore
FROM
(
SELECT name,
CAST(50 /
(
select 1.0 + MAX(LDist)
FROM
(
select startAt.number,
LEN(longer) -
sum(case when SUBSTRING(longer, startAt.number+offset.number, 1)
= SUBSTRING(shorter, 1+offset.number, 1) then 1 else 0 end ) LDist
FROM
(select case when LEN(Name) < LEN(LookFor) then Name else LookFor end shorter) shorter
cross join
(select case when LEN(Name) >= LEN(LookFor) then Name else LookFor end longer) longer
inner join master..spt_values startAt
on startAt.type='P' and startAt.number between 1 and len(longer) - LEN(shorter) + 1
inner join master..spt_values offset
on offset.type='P' and offset.number between 0 and LEN(shorter)-1
group by startAt.number, longer, shorter
) X
) AS NUMERIC(16,4)) SCORE_Levenshtein
,
CAST(50 / (5- -- inversely proportional to soundex difference
(
SELECT 0.0 +
case when Substring(A,1,1)=Substring(B,1,1) then 1 else 0 end
+
case when Substring(A,2,1)=Substring(B,2,1) then 1 else 0 end
+
case when Substring(A,3,1)=Substring(B,3,1) then 1 else 0 end
+
case when Substring(A,4,1)=Substring(B,4,1) then 1 else 0 end
FROM (select soundex(name) as A, SOUNDEX(LookFor) as B) X
)) AS NUMERIC(16,4)) AS SCORE_SOUNDEX
FROM tbl
CROSS JOIN (SELECT 'Jon' as LookFor) LookFor
) Scored
Order by SCORE_Levenshtein + SCORE_SOUNDEX DESC
注意 - 使用此行 CROSS JOIN (SELECT 'Jon' as LookFor) LookFor
以便输入 'Jon'
不需要在查询中重复多次。也可以定义一个变量,并在查询中使用LookFor
的地方使用它。
输出
值得注意的是,Jonny 与 SOUNDEX 一起获得了高于 Bone 的分数,而单独使用 Levenshtein
不会发生这种情况。
name SCORE_Levenshtein SCORE_SOUNDEX TotalScore
Jon 50.0000 50.0000 100.0000
John 12.5000 50.0000 62.5000
Jonny 8.3333 50.0000 58.3333
Jonne 8.3333 50.0000 58.3333
Bone 10.0000 25.0000 35.0000
BJon 10.0000 12.5000 22.5000
Jonathan 5.5556 16.6667 22.2223
Nathan 7.1429 12.5000 19.6429
原始答案如下,基于基于 LIKE '%x%' 的预过滤输入,它将 Levenshtein 折叠为简单的 Len(column) - Len(Like-expression) 计算
看看这个例子 - 它测试了长度和 SOUNDEX 的差异,因为没有更好的度量。
最高分是 100。
;with tbl as (
select 'Jon' AS Name union all
select 'Jonathan' union all
select 'Jonny' union all
select 'John' union all -- doesn't match LIKE
select 'BJon' union all
select 'Jonne')
SELECT name,
50 / (Len(Name) - LEN('Jon') + 1.0) -- inversely proportional to length difference
+
50 / (5- -- inversely proportional to soundex difference
(
SELECT 0.0 +
case when Substring(A,1,1)=Substring(B,1,1) then 1 else 0 end
+
case when Substring(A,2,1)=Substring(B,2,1) then 1 else 0 end
+
case when Substring(A,3,1)=Substring(B,3,1) then 1 else 0 end
+
case when Substring(A,4,1)=Substring(B,4,1) then 1 else 0 end
FROM (select soundex(name) as A, SOUNDEX('Jon') as B) X
)) AS SCORE
FROM tbl
where name LIKE '%Jon%'
Order by SCORE DESC
输出
name SCORE
Jon 100.00000000000000000
Jonny 66.66666666666660000
Jonne 66.66666666666660000
BJon 37.50000000000000000
Jonathan 24.99999999999996666
【讨论】:
我喜欢你批评 Levenstein 距离的适用性,然后提出糟糕的 SOUNDEX 实现的方式! ***.com/questions/42013/… @Mitch - 让我们看看你的建设性回答【参考方案3】:这样的事情可能会有所帮助:
http://www.mombu.com/microsoft/microsoft/t-equivalent-sql-server-functions-for-match-against-in-mysql-2292412.html
【讨论】:
以上是关于sql 数据库可以返回一个 sql 结果集加上结果的分数吗?的主要内容,如果未能解决你的问题,请参考以下文章
oracle 存储过程执行动态SQL 返回结果给游标,外部程序获得dataset结果集。