计算具有多个匹配项的分数

时间:2018-08-10 05:41:55

标签: sql sql-server tsql stored-procedures

我正在尝试创建一个存储过程,该过程进行搜索并根据匹配项计算分数。

DECLARE @Search VARCHAR(MAX) = 'John Doe Washington';

SELECT
[address].Name,
[address].Street,
[address].City,
[address].ZipCode,
[address].Country,
IIF([address].[Name] LIKE '%'+@Search+'%', 1000, 0)
 + IIF([address].[Street] LIKE '%'+@Search+'%', 800, 0)
  + IIF([address].[City] LIKE '%'+@Search+'%', 750, 0)
   + IIF([address].[ZipCode] LIKE '%'+@Search+'%', 300, 0)
    + IIF([address].[Country] LIKE '%'+@Search+'%', 250, 0) AS [Score]
FROM [dbo].[Addresses] AS [address];

如果我只是使用例如Name列中可能包含“ John Doe”。

但是我想稍后用逗号分割@Search参数,该参数与我发现here的函数[dbo].[splitstring](@stringToSplit VARCHAR(MAX))一起使用。该函数按逗号分割并创建多行。

所以现在我想更改查询,以使多个搜索词都可以使用。 我想要的是一个LIKE IN(SELECT '%'+Value+'%' FROM dbo.splitstring(@Search)),不幸的是,它在MS SQL Server中不存在。

如果多个单词与该列匹配,则得分应更高。这意味着该列包含“ John Doe”,第一个单词“ John”匹配1000点,第二个单词“ Doe”匹配另外1000点。第三个是“华盛顿”,它不匹配,所以这个将是0分。

有没有办法做到这一点,或者在MS SQL Server中目前无法做到?

4 个答案:

答案 0 :(得分:1)

与其进行LIKE IN (select...联接,而不是进行联接

cross join (select '%'+Value+'%' as val FROM dbo.splitstring(@Search)) as words

然后您可以对所有行的分数求和

sum(IIF([address].[Name] LIKE val, 1000, 0)
 + IIF([address].[Street] LIKE val, 800, 0)
  + IIF([address].[City] LIKE val, 750, 0)
   + IIF([address].[ZipCode] LIKE val, 300, 0)
    + IIF([address].[Country] LIKE val, 250, 0)
) AS [Score]

哦,然后将函数中的分隔符从逗号更改为空格。

答案 1 :(得分:0)

以i / p程序获取XML。请参考下面的示例。

<data>
    <Name>John Doe</Name>
    <Street>Cross Road</Street>
    <City>Washington</City>
    <ZipCode>188255</ZipCode>
    <Country>US</Country>
</data>

将此数据插入名称为“名称”,“街道”,“城市”的列的临时表中,并将表与列对列一起应用。

答案 2 :(得分:0)

使用WHERE myColumn LIKE '%word%'是多余的,因为它与WHERE SUBSTRING('word', myColumn) > 0完全相同。因此,您的条件是:

WHERE myColumn LIKE IN(SELECT '%'+Value+'%' FROM dbo.splitstring(@Search))

变得可能和容易:

WHERE EXISTS(SELECT 1 FROM dbo.splitstring(@Search)
             WHERE SUBSTRING([Value], myColumn) > 0)

此外,您可能需要将表别名添加到子查询myTable.myColumn中。

答案 3 :(得分:0)

或者,您可以省略自定义功能并使用一个查询(有意地分步编写):

DECLARE @terms nvarchar(MAX) = N'John,Doe,Wood';

WITH SourceTable AS --demo data, skip, use your Addresses table instead
(
  SELECT * FROM (VALUES
  ('John Doe', 'Street'),
  ('John Cooper', 'Wood')) T(Name,Street)
), Query AS --convert to xml
(
  SELECT CAST('<a>'+REPLACE(@terms,',','</a><a>')+'</a>' as xml) Query
), SimpleTerms AS --split to rows
(
    SELECT Term.value('.', 'nvarchar(MAX)') Term
    FROM Query
    CROSS APPLY Query.nodes('a') AS T(Term)
)
SELECT Name,Street,
  SUM(IIF(Name LIKE '%'+Term+'%',1000,0)) +
  SUM(IIF(Street LIKE '%'+Term+'%',100,0)) Score
  --other ingredients
FROM SourceTable
CROSS APPLY SimpleTerms
GROUP BY Name,Street