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
时会盲目地计算abcsessions
或sessionsxyz
。如果需要更复杂的东西(例如考虑单词边界),您可能需要使用正则表达式替换器而不是 REPLACE
函数 - 但不幸的是,这是 mysql 缺乏的一件事。我曾经尝试过写一篇文章,但这并不简单 - 请参阅 here。
【讨论】:
谢谢史蒂夫,这看起来很有希望,我会在开始工作后对其进行测试。如果我遇到问题,我可能会稍后联系您。我昨天下班前开始使用正则表达式,但您的解决方案看起来更加优雅。 没有问题。我猜你已经知道 MySQL 提供了REGEXP
函数,可以很容易地用于计算 record_count
- 只需执行类似 WHERE request REGEXP CONCAT('[[:<:]]', id, '[[:>:]]')
的操作(有关更多信息,请参阅 here)。只有occurrence_count
需要替换来计算单个字段值中出现的次数。以上是关于SQL计算第二个表中一个表中单词的出现次数的主要内容,如果未能解决你的问题,请参考以下文章