繁体   English   中英

基于两个表的SQL最高记录关系

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM