SQL计算第二个表中一个表中单词的出现次数

Posted

技术标签:

【中文标题】SQL计算第二个表中一个表中单词的出现次数【英文标题】:SQL count the occurrences of words from one table in second table 【发布时间】:2017-01-09 17:46:02 【问题描述】:

我正在尝试使用 SQL 方言来解析一组记录。具体来说,我想计算我的日志中出现的包含各种 id(单词)的记录数。我还想计算这些 id 出现的总次数。

数据存在于两个不同的表中:

id_status - 包含id,status 的表。 request_records - 包含请求记录的表。 id 可能在给定记录中出现多次。

见SQL Fiddle!

id_status

此表包含 id 及其当前状态。

id, status
sessions, ACTIVE
visits, DEPRECATED
duration, ACTIVE
...

request_records

句子记录可能包含超过 30 万条记录:

request
example.com/api?foo=sessions
example.com/api?bar=session%2Cvisits,foo=sessions
example.com/api?bar=duration,visits
example.com/api?foo=sessions
example.com/api?foo=visits,bar=visits
...

目标

我想创建一个包含四列id,status,occurence_count,record_count 的表。

occurence_count: 应该是 id 在所有记录中出现的总次数。 recourd_count:应该是特定 id 出现的记录总数。

根据上述示例,我将生成下表:

id, status, occurence_count, recourd_count
sessions,ACTIVE,3,2
visits,DEPRECATED,4,3
duration,ACTIVE,1,1

SQL

有没有办法构造一个返回所需表的 SQL 查询?我会知道如何用 Python 或任何其他语言相当容易地做到这一点,但如果可能的话,我想写一个 SELECT 语句来生成这个表。

更新:如下所示,我已尝试执行以下操作:

SELECT ids.id, ids.status,
     SUM(length(request) - LENGTH(replace(request, ids.id, ''))) / LENGTH(ids.id) as occurence_count,
     COUNT(reqs.request) AS recourd_count
FROM id_status ids LEFT JOIN
     request_records reqs
     ON find_in_set(ids.id, reqs.requests) > 0
GROUP BY ids.id, ids.status;

但是我的 SQL 方言不允许这种类型的连接并返回以下错误:

ON clause must be AND of = comparisons of one field name from each table, with all field names prefixed with table name.

添加了Sample Schema的SQL Fiddle:

CREATE TABLE id_status
    (`id` varchar(32), `status` varchar(32))
;

INSERT INTO id_status
    (`id`, `status`)
VALUES
    ('sessions', 'ACTIVE'),
    ('visits', 'DEPRECATED'),
    ('duration', 'ACTIVE')
;

CREATE TABLE request_records 
    (`request` varchar(500))
;

【问题讨论】:

见meta.***.com/questions/333952/… 您想要完全匹配的单词吗?比如sentencerecord表的第一条记录,是计算一​​次还是两次? @karan Shah:所以,我正在寻找单词出现的总次数和记录数。所以第一条记录将使总计数增加 2,并且按 1 记录发生次数。 我想你已经得到了答案,如果你需要再看看,请告诉我 @Strawberry,我已经更新了问题,将SQL Fiddle sample Schema 包含在建议的解决方案失败的情况下,并将问题重新表述得更清楚。请重新打开或提供有关如何改进问题以使其可回答的更多详细信息? 【参考方案1】:

您可以通过查询生成所需的内容。它不会有效率:

select w.word, w.status,
       sum(length(sentence) - length(replace(sentence, w.word, ''))) / length(w.word) as cnt,
       count(s.sentence) as num_occurrences
from words w left join
     sentences s
     on find_in_set(w.word, s.sentence) > 0
group by w.word, w.status;

【讨论】:

我对此表示赞同,但仅供参考,如果“单词”包含另一个“单词”,此解决方案将不起作用。例如,如果您有一个句子“duration,visits,sessions,new-sessions”,则为“sessions”列出的计数将大于实际应有的值。如果这是一个问题,请考虑将逗号连接到每个句子的末尾,然后将单词 +',' 替换为空字符串。在这种情况下,您必须除以 length(w.word) + 1。但实际上,如果这是一种需要重复执行的查询,那么重组您的数据库可能是值得的。 @VKK 。 . .你的评论非常真实。对于 OP 似乎正在使用的逗号分隔列表,有一个解决方案,但它确实使表达式更加混乱。 所以我已将您的解决方案添加到问题中,您可以从 sql fiddle 中看到它并没有完全给出我正在寻找的答案,但感谢您的帮助。【参考方案2】:

简单版:

SELECT id,
       status,
       (SELECT (SUM(CHAR_LENGTH(request)) -
                SUM(CHAR_LENGTH(REPLACE(request, id, ''))))
               / CHAR_LENGTH(id) FROM request_records) AS occurrence_count,
       (SELECT COUNT(*)
        FROM request_records
        WHERE INSTR(request, id) > 0) AS record_count
FROM id_status

见updated SQL fiddle。

这只是寻找出现在任何地方的单词,例如在寻找sessions 时会盲目地计算abcsessionssessionsxyz。如果需要更复杂的东西(例如考虑单词边界),您可能需要使用正则表达式替换器而不是 REPLACE 函数 - 但不幸的是,这是 mysql 缺乏的一件事。我曾经尝试过写一篇文章,但这并不简单 - 请参阅 here。

【讨论】:

谢谢史蒂夫,这看起来很有希望,我会在开始工作后对其进行测试。如果我遇到问题,我可能会稍后联系您。我昨天下班前开始使用正则表达式,但您的解决方案看起来更加优雅。 没有问题。我猜你已经知道 MySQL 提供了 REGEXP 函数,可以很容易地用于计算 record_count - 只需执行类似 WHERE request REGEXP CONCAT('[[:<:]]', id, '[[:>:]]') 的操作(有关更多信息,请参阅 here)。只有occurrence_count 需要替换来计算单个字段值中出现的次数。

以上是关于SQL计算第二个表中一个表中单词的出现次数的主要内容,如果未能解决你的问题,请参考以下文章

sql server 2000返回在第一个表中但不在第二个表中的数据

将第二个表中的第二个(条件)结果添加到 SQL 查询

T-SQL:比较两个表 - 第二个表中不存在的记录

SQL LEFT JOIN 从第二个表中排除两条记录

在不借助 PL/SQL 的情况下从第二个表中查找相关值

如何将两个表与 SQL Server 中第二个表中引用同一列的两列连接起来