SQL顶级记录基于两个表的关系

时间:2014-11-04 17:06:08

标签: mysql sql foreign-key-relationship has-many

我有三个主要项目:文章,实体和关键字。这使得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.. ]
);

4 个答案:

答案 0 :(得分:2)

如果我理解你正确的话,查询的目的是找到与前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个关键字一样受欢迎,它仍然无法获得选择。这可以通过使用排名函数来修复,但是没有内置任何东西(如Oracle或MSSQL中的RANK()窗口函数)。

我设置了一个示例SQL Fiddle(但是我使用的数据点更少,limit 2因为我很懒。)

答案 1 :(得分: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

答案 2 :(得分:1)

我分几步采取了这个步骤

tl; dr 这会显示top(4)关键字和实体中的所有文章:

这是fiddle

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似乎适用于我想在小提琴中制作的协会数量)

我不想在这里选择文章,因为它会使群体产生偏差,你只想专注于顶级实体。 Fiddle

select
  entity_id, count(*)
from
  article_entity
group by
  entity_id
order by 
  count(*) desc
limit 4

然后我选择了这些顶级实体的所有文章。 Fiddle

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放在一起(fiddle),并从联合中提取不同的文章ID。

这将为您提供与top(x)实体和关键字有关的所有文章。

答案 3 :(得分:0)

这将获得前十大关键字文章,这些文章也是十大实体。您可能无法获得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