按匹配词数排序

时间:2018-10-25 15:53:59

标签: sql sql-server tsql azure-sql-database

我写下了一个查询,但它不能完全满足我的需求。 我想获取包含单词列表的所有行,并按在字符串中找到的这些单词的数量对其进行排序。

这是我的数据示例:

+--------+------------------------------+
| ITM_ID |           ITM_Name           |
+--------+------------------------------+
|      1 | Blue Shirt with white collar |
|      2 | Party dress                  |
|      3 | Black derbies with cap toe   |
|      4 | Sky blue dress               |
+--------+------------------------------+

如果我使用“ blue”和“ dress”这两个词进行搜索,则需要以下结果:

+---+------------------------------+
| 4 | Sky blue dress               |
| 1 | Blue Shirt with white collar |
| 2 | Party dress                  |
+---+------------------------------+

“天蓝色连衣裙”位于列表顶部,因为我们找到了两个单词,而不是其他字符串中的一个。

我想出了如何使用CONTAINS搜索单词:

SELECT ITM_ID, ITM_Name, CHARINDEX(
FROM T_Item_ITM
WHERE CONTAINS(ITM_Name, 'dress OR blue')

但是我找不到该订单的解决方案。你是否有一个 ?

谢谢。

2 个答案:

答案 0 :(得分:1)

您可以使用string_split隔离单个单词,然后使用group by对其计数。

declare @tmp table (ITM_ID int ,  ITM_Name nvarchar(100))
insert @tmp values
     (1 ,'Blue Shirt with white collar')
    ,(2 ,'Party dress')
    ,(3 ,'Black derbies with cap toe')
    ,(4 ,'Sky blue dress')

select a.*
from (
    select t.ITM_ID
        ,count(*) as result_count
    from @tmp t
    cross apply string_split(ITM_Name, ' ') w
    where w.[value] in (
            'blue'
            ,'dress'
            )
    group by ITM_ID
    ) c
inner join @tmp a
    on a.ITM_ID = c.ITM_ID
order by c.result_count desc

结果:

enter image description here

请注意,如果您还有其他标点符号(逗号,分号等),则在分割之前必须将其替换为空格。

答案 1 :(得分:0)

这是另一种方法:

DECLARE @Data TABLE (
    Id INT,
    Name VARCHAR(100)
);
INSERT INTO @Data VALUES
    (1, 'Blue Shirt with white collar'),
    (2, 'Party dress'),
    (3, 'Black derbies with cap toe'),
    (4, 'Sky blue dress');

DECLARE @Terms TABLE (
    Value VARCHAR(100)
);
INSERT INTO @Terms VALUES 
    ('dress'),
    ('blue');

WITH TermOccurrences AS (
    SELECT *, (LEN(d.Name) - LEN(REPLACE(d.Name, t.Value, ''))) / LEN(t.Value) AS NumOccurrences
    FROM @Data d
        INNER JOIN @Terms t ON d.[Name] LIKE '%' + t.Value + '%'
), TotalOccurrences AS (
    SELECT Id, SUM(NumOccurrences) AS TotalMatches
    FROM TermOccurrences
    GROUP BY Id
)
SELECT d.Id, d.Name, tot.TotalMatches
FROM TotalOccurrences tot
    INNER JOIN @Data d ON d.Id = tot.Id
ORDER BY tot.TotalMatches DESC

这会通过用空字符串替换术语并将原始名称的长度与没有术语的名称的长度进行比较来检查术语的出现次数。

我无法说出这种效果,但这是您可以尝试的另一种方法。