簡體   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