【问题标题】:MySQL sort by number of occurrencesMySQL按出现次数排序
【发布时间】:2014-04-03 16:15:24
【问题描述】:

我正在两个名为 SubjectText 的文本字段中搜索特定关键字。为此,我使用LIKE 语句。我在尝试按出现次数对结果进行排序时遇到问题。

我的搜索查询如下所示:

SELECT * FROM Table WHERE (Text LIKE '%Keyword%' OR Subject LIKE '%Keyword%')

我尝试添加一个 count() 语句并按出现次数对其进行排序,但 count() 语句只是不断返回我的表中的行数。

这里是带有count语句的查询:

SELECT *, COUNT(Text LIKE '%Keyword%') AS cnt FROM News WHERE (Text LIKE '%Keyword%' OR Subject LIKE '%Keyword%') ORDER BY cnt

我正在寻找的是返回每行主题和文本列上的匹配数,然后在每行关键字出现次数最多之后对结果进行排序。

【问题讨论】:

  • 您想按关键字在文本中出现的次数或关键字在表格中出现的次数进行排序?
  • 你可以使用substr_count提到的mysql函数here
  • 我认为全文搜索 (dev.mysql.com/doc/refman/5.0/en/fulltext-search.html) 可能是您的朋友。
  • 我尝试了全文搜索的方式,但它似乎可以整理出存在于多行中的常用词。由于我没有很长的文本,并且某些关键字将存在于不止一行中,如果我正确理解全文搜索,它会专注于每一行唯一的单词,因此我决定尝试寻找另一种方法。这是正确的还是我在尝试全文搜索时做错了什么?

标签: php mysql database web


【解决方案1】:

下面的查询可以为您提供出现在两列(即文本和主题)中的字符串的出现次数,并将按条件对结果进行排序,但这不是一个好的解决方案性能,最好在应用程序代码中对结果进行排序等级

SELECT *,
(LENGTH(`Text`) - LENGTH(REPLACE(`Text`, 'Keyword', ''))) / LENGTH('Keyword')
+
(LENGTH(`Subject`) - LENGTH(REPLACE(`Subject`, 'Keyword', ''))) / LENGTH('Keyword') `occurences`
 FROM 
`Table`
 WHERE (Text LIKE '%Keyword%' OR Subject LIKE '%Keyword%')
ORDER BY `occurences`  DESC

Fiddle Demo

@lserni提出了一种更简洁的计算出现次数的方法

SELECT *,
(LENGTH(`Text`) - LENGTH(REPLACE(`Text`, 'test', ''))) / LENGTH('test') `appears_in_text`,

(LENGTH(`Subject`) - LENGTH(REPLACE(`Subject`, 'test', ''))) / LENGTH('test') `appears_in_subject`,

(LENGTH(CONCAT(`Text`,' ',`Subject`)) - LENGTH(REPLACE(CONCAT(`Text`,' ',`Subject`), 'test', ''))) / LENGTH('test') `occurences`
 FROM 
`Table1`
 WHERE (TEXT LIKE '%test%' OR SUBJECT LIKE '%test%')
ORDER BY `occurences`  DESC

Fiddle Demo 2

【讨论】:

  • 您需要除以关键字的长度以获得正确的出现次数
  • 您还可以检查使用 (LENGTH(CONCAT(Subject,',',Text))-LENGTH(REPLACE(CONCAT(Text,',' ,Subject),'Keyword',''))/LENGTH('Keyword') 运行单个,尽管更长,替换。
  • @lserni 感谢您的好消息,我也会尝试使用 concat 进行小提琴并在我的答案中发布
  • 小提琴中的结果正是我想要的。我只需要一点时间来弄清楚你在 MySQL 部分做了什么,因为我对 MySQL 没有太多经验:)
  • 弄清楚它现在是如何工作的,就像一个魅力!非常感谢! :)
【解决方案2】:

你想要SUM。 Count 将计算有多少条记录具有非空值,这意味着将计算所有匹配项和非匹配项。

SELECT *, SUM(Text LIKE '%Keyword') AS total_matches
...
ORDER BY total_matches

SUM() 将计算 LIKE 产生的布尔真结果的数量,这些结果将被类型转换为整数,因此您得到的结果类似于 1+1+1+0+1 = 4,而不是 5 个非空值数。

【讨论】:

  • 我想他想知道关键字在单个元组中出现了多少次SUM('So the quick brown fox jumped over the lazy dog' LIKE '%the%') 返回 1,我认为他想要返回 2 的东西。
  • 是的,尝试了这个,正如 Iserni 所说,我正在寻找返回每个搜索行的出现次数的东西,然后对其进行排序。我错过了问题中的那一部分,将解决它:)
【解决方案3】:
// escape $keyword for mysql
$keyword = strtolower('Keyword');
// now build the query
$query = <<<SQL
    SELECT *,
    ((LENGTH(`Subject`) - LENGTH(REPLACE(LOWER(`Subject`), '{$keyword}', ''))) / LENGTH('{$keyword}')) AS `CountInSubject`,
    ((LENGTH(`Text`) - LENGTH(REPLACE(LOWER(`Text`), '{$keyword}', ''))) / LENGTH('{$keyword}')) AS `CountInText`
    FROM `News`
    WHERE (`Text` LIKE '%{$keyword}%' OR `Subject` LIKE '%{$keyword}%')
    ORDER BY (`CountInSubject` + `CountInText`) DESC;
SQL;

返回每个字段中出现的次数并按此排序。

'keyword' 需要小写才能正常工作。我不认为它真的很快,性能明智,因为它需要小写字段并且在 MySQL afaik 中没有不区分大小写的搜索。

您可以按单词索引每个news 项目subjecttext,并使用news_id 和出现次数存储在另一个表中,然后与之匹配。

【讨论】:

    猜你喜欢
    • 2011-05-16
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    相关资源
    最近更新 更多