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