[英]SQL top records based on two tables relations
我要存储三个主要项目:文章,实体和关键字。 这产生了5个表:
article { id }
entity {id, name}
article_entity {id, article_id, entity_id}
keyword {id, name}
article_keyword {id, article_id, keyword_id}
我想获取所有包含TOP X关键字+实体的文章。 我可以通过entity_id/keyword_id
通过一个简单的组来获取排名靠前的X个关键字或实体。
SELECT [entity|keyword]_id, count(*) as num FROM article_entity
GROUP BY entity_id ORDER BY num DESC LIMIT 10
如何获得与顶级实体和关键字相关的所有文章?
这就是我的想象,但是我知道它是行不通的,因为逐个实体限制了article_id的返回值。
SELECT * FROM article
WHERE EXISTS (
[... where article is mentioned in top X entities.. ]
) AND EXISTS (
[... where article is mentioned in top X keywords.. ]
);
如果我理解正确,那么查询的目的是找到与前10个实体之一和前10个关键字之一都相关的文章。 如果是这种情况,则以下查询应这样做,即要求返回的文章在前10个实体的集合和前10个关键字的集合中都具有匹配项。
请试一试。
SELECT a.id
FROM article a
INNER JOIN article_entity ae ON a.id = ae.article_id
INNER JOIN article_keyword ak ON a.id = ak.article_id
INNER JOIN (
SELECT entity_id, COUNT(article_id) AS article_entity_count
FROM article_entity
GROUP BY entity_id
ORDER BY article_entity_count DESC LIMIT 10
) top_ae ON ae.entity_id = top_ae.entity_id
INNER JOIN (
SELECT keyword_id, COUNT(article_id) AS article_keyword_count
FROM article_keyword
GROUP BY keyword_id
ORDER BY article_keyword_count DESC LIMIT 10
) top_ak ON ak.keyword_id = top_ak.keyword_id
GROUP BY a.id;
在顶级实体/关键字的两个子查询中使用简单的limit 10
的不利之处在于它将无法处理联系,因此,如果第11个关键字与第10个关键字一样受欢迎,那么仍然不会被选择。 尽管可以通过使用排名函数来解决此问题,但是afaik MySQL没有内置任何功能(例如Oracle或MSSQL中的RANK()窗口函数)。
我设置了一个示例SQL Fiddle (但由于我很懒,所以使用了更少的数据点和limit 2
)。
不知道要使用的数据量,我首先建议您在商品表上有两个存储列,分别用于实体和关键字的计数。 然后通过添加/删除触发器,更新相应的计数器列。 这样,您不必每次都需要执行刻录查询,尤其是在基于Web的界面中。 然后,您只需从按E + K计数降序排列的商品表中进行选择即可,而不用对子表进行常量子查询。
就是说,其他建议与我发布的建议有些相似,但它们似乎都限制每组10条记录。 让我们把这种情况付诸实践。 假设您有1-20条文章,其中包含10、9和8个实体以及1-2个关键字。 那么文章21-50具有相反的... 10、9、8个关键字和1-2个实体。 现在,您拥有的文章51-58具有7个实体和7个关键字,总共14个组合点。 由于实体只会返回符合条件的1-20条记录和关键字记录21-50,因此这些查询都无法捕获到该查询。 第51-58条将排在最后,即使总数为14,也不会被考虑。
为了解决这个问题,每个子查询都是一个完整的查询,专门针对商品ID及其数量。 按article_ID进行简单排序,这是联接到主商品表的基础。
现在,如果有的话,coalesce()将获得计数,否则返回0并将两个值相加。 由此,在应用限制时,结果将首先以最高计数(因此获得场景样本文章51-58和其他一些)进行排序。
SELECT
a.id,
coalesce( JustE.ECount, 0 ) ECount,
coalesce( JustK.KCount, 0 ) KCount,
coalesce( JustE.ECount, 0 ) + coalesce( JustK.KCount, 0 ) TotalCnt
from
article a
LEFT JOIN ( select article_id, COUNT(*) as ECount
from article_entity
group by article_id
order by article_id ) JustE
on a.id = JustE.article_id
LEFT JOIN ( select article_id, COUNT(*) as KCount
from article_keyword
group by article_id
order by article_id ) JustK
on a.id = JustK.article_id
order by
coalesce( JustE.ECount, 0 ) + coalesce( JustK.KCount, 0 ) DESC
limit 10
我把这个几个步骤
tl; dr这显示了前(4)个关键字和实体中的所有文章:
这是一个小提琴
select
distinct article_id
from
(
select
article_id
from
article_entity ae
inner join
(select
entity_id, count(*)
from
article_entity
group by
entity_id
order by
count(*) desc
limit 4) top_entities on ae.entity_id = top_entities.entity_id
union all
select
article_id
from
article_keyword ak
inner join
(select
keyword_id, count(*)
from
article_keyword
group by
keyword_id
order by
count(*) desc
limit 4) top_keywords on ak.keyword_id = top_keywords.keyword_id) as articles
说明:
这始于寻找前X个实体的努力。 (4个似乎对我想在小提琴中建立的协会数量起作用)
我不想在这里选择文章,因为它歪曲了分组依据,您只想专注于顶级实体。 小提琴
select
entity_id, count(*)
from
article_entity
group by
entity_id
order by
count(*) desc
limit 4
然后,我从这些顶级实体中选择了所有文章。 小提琴
select
*
from
article_entity ae
inner join
(select
entity_id, count(*)
from
article_entity
group by
entity_id
order by
count(*) desc
limit 4) top_entities on ae.entity_id = top_entities.entity_id
显然,关键字需要发生相同的逻辑。 该查询然后union
编在一起( 小提琴 )和不同的文章ID是从工会拉动。
这将为您提供与前(x)个实体和关键字相关的所有文章。
这将获得前10个关键字文章,同时也是前10个实体。 您可能不会获得10条记录,因为一篇文章可能仅满足以下条件之一(最高实体,但不符合最高关键字,或者最高关键词,但不符合最高实体)
select *
from article a
inner join
(select count(*),ae.article_id
from article_entity ae
group by ae.article_id
order by count(*) Desc limit 10) e
on a.id = e.article_id
inner join
(select count(*),ak.article_id
from article_keyword ak
group by ak.article_id
order by count(*) Desc limit 10) k
on a.id = k.article_id
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.