Mysql 基于两表关系的SQL top记录
我存储三个主要项目:文章、实体和关键字。这包括5个表:Mysql 基于两表关系的SQL top记录,mysql,sql,foreign-key-relationship,has-many,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} 我想得到所有的文章,包含前X关键字+实体。我可以通过实体id/keyword\u id上的一个简单的分组获得前X个关键字或实体 SELECT [entity|ke
article { id }
entity {id, name}
article_entity {id, article_id, entity_id}
keyword {id, name}
article_keyword {id, article_id, keyword_id}
我想得到所有的文章,包含前X关键字+实体。我可以通过实体id/keyword\u id
上的一个简单的分组获得前X个关键字或实体
SELECT [entity|keyword]_id, count(*) as num FROM article_entity
GROUP BY entity_id ORDER BY num DESC LIMIT 10
如何获取与顶级实体和关键词相关的所有文章?
这是我想象的,但我知道这不起作用,因为逐实体分组限制了文章id的返回
SELECT * FROM article
WHERE EXISTS (
[... where article is mentioned in top X entities.. ]
) AND EXISTS (
[... where article is mentioned in top X keywords.. ]
);
我采取了几个步骤 tl;dr这显示了前(4)个关键词和实体中的所有文章: 这里有一个 说明: 首先要努力找到最上面的X个实体。(4似乎对我想在小提琴中建立的联想数量起作用) 我不想在这里选择文章,因为它会使组倾斜,因为您希望只关注顶级实体 然后我从这些顶级实体中选择了所有文章 显然,关键字也需要同样的逻辑。然后将查询
union
ed放在一起(),并从union中提取不同的项目ID
这将为您提供与前(x)个实体和关键字相关的所有文章。这将获得前10个关键字文章,它们也是前10个实体。您可能无法取回10条记录,因为一篇文章可能只满足其中一个条件(top entity但不满足top关键字或top关键字但不满足top entity)
如果我理解你的意思,那么查询的目的是找到与前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;
在顶级实体/关键字的两个子查询中使用简单的限制10
的缺点是它不会处理关系,因此,如果第11个关键字与第10个关键字一样流行,它仍然不会被选中。这可以通过使用ranking函数来修复,但是afaik-MySQL没有任何内置功能(比如Oracle或MSSQL中的RANK()窗口函数)
我设置了一个示例(但使用较少的数据点和
限制2
,因为我很懒)。由于不知道您正在处理的数据量,我首先建议您在文章表中分别设置两个存储列,用于实体和关键字的计数。然后通过添加/删除每个计数器的触发器,更新相应的计数器列。这样,您就不必在每次需要时都执行烧录查询,尤其是在基于web的界面中。然后,您只需从按E+K计数降序排列的articles表中进行选择,然后就可以使用它来完成操作,而不是对基础表进行常量子查询
现在,也就是说,其他的建议与我发布的内容有些相似,但它们似乎都限制了每套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及其计数。按项目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
实体
和关键字
表没有重复项。每个实体和关键字只使用一次,因此子查询中的COUNT(*)
没有意义。也许您打算对实体文章
或关键字文章
表进行全部计数?这些可能会有多个结果。我根据您的反馈更新了我的答案。在子查询中,您可以只使用映射表,因为这是真正的计数,但我将它们加入到相应的表中,以防您想验证您的查询是否正确。此外,我相信你只会给出这个查询中关键词最多的10篇文章。而不是前10个关键词中的文章/entities@Xeoncross我已经更新了我的查询并给出了一些解释,包括SQLFIDLE链接。我相信这就是你需要的答案。查询可能会被缩短,我会考虑,但希望你对结果作出反应。如果你愿意,考虑下面这个简单的两步行动:1。如果您还没有这样做,请提供适当的DDL(和/或SQLFIDLE),以便我们可以更轻松地复制问题。2.如果您还没有这样做,请提供一个与步骤1中提供的信息相对应的所需结果集。@草莓,请您避免一般性的复制/粘贴,即告诉某人放置DLL并转到SQL FIDLE。有了所提供的信息,那些流利的人可以理解,我知道我已经看到了太多的这些粘贴评论。我提供了一个答案,另一个注意到我可能误解了你想要的,但不相信我这么做了。让我知道,如果我的目标与你正在寻找的。。。谢谢,我认为你提到了一个正确的观点,那就是消极选择适合一套但不适合另一套的文章
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
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
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;
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