2015-09-10 48 views
0

我正在使用一個系統,用戶可以將標籤附加到消息上以便於搜索/識別(就像這裏一樣)。這是簡化的架構:查找與標籤組相關的標籤

message: message_id 
tag: tag_id, tag_name 
tag_message: tag_id (FK), message_id (FK) 

我面臨的問題是:

鑑於tag_id的輸入列表,我想找到什麼其他的標記出現在標記有在輸入的信息標籤

這是我想出了查詢:

SELECT 
    tag2.tag_name, 
    COUNT(*) AS tagged_message_count 

FROM tag AS tag1 
    LEFT JOIN tag_message     ON tag_message.tag_id = tag1.tag_id 
    LEFT JOIN message      ON message.message_id = tag_message.message_id 
    LEFT JOIN tag_message AS tag_message2 ON tag_message2.message_id = message.message_id 
    LEFT JOIN tag   AS tag2   ON tag_message2.tag_id = tag2.tag_id 
WHERE 
    tag1.tag_id = ? 
AND 
    tag1.tag_id <> tag2.tag_id 
GROUP BY 
    tag2.tag_id; 

作品但它只適用於1個標籤,我需要它與標籤組合作。

鑑於標籤ID 1,2,3我們應該首先找到所有標有這三個標籤的郵件,然後查看其他標籤並返回它們。

我有一種感覺,每個標籤都會有額外的連接,但是我不確定如何修改查詢來修改它。

+0

'...標記有這三個標籤,...' :**全部**這三個標籤,或者**這三個標籤中的任何**? – joop

+0

所有這三個標籤都需要附加到郵件中,我們通過標籤過濾郵件(我們只想要包含所有這些標籤的郵件,但可能還有其他一些) – Eleeist

回答

1

可以使用發現標記爲1,2, 3消息:

select tm.message_id 
from tag_message tm 
where tm.tag_id in (1, 2, 3) 
group by tm.message_id 
having count(*) = 3; 

您可以使用找到其他標籤:

select tag_id, count(*) 
from tag_message 
where message_id in (select tm.message_id 
        from tag_message tm 
        where tm.tag_id in (1, 2, 3) 
        group by tm.message_id 
        having count(*) = 3 
        ) and 
     tag_id not in (1, 2, 3) 
group by tag_id 
order by count(*) desc; 

如果你想有標籤1的消息, 2, 3,然後刪除having子句。

+0

謝謝,第二個查詢是我正在查找的內容。查詢不會按原樣編譯,因爲您在第一個查詢中忘記了GROUP BY,在第二個示例中忘記了嵌套查詢。這兩個修復程序後,它按預期工作:) – Eleeist

0

這可能過於複雜,但它至少是一種替代解決方案...


 -- For convience: put the arguments to the query into a CTE 
     -- (a temp table *could* be faster for larger sets) 
     -- ------------------------------------------- 
WITH args(tagid) AS (
    VALUES (2), (3) , (4) 
    ) 
     -- messages that have ALL the tags 
     -- [the double NOT EXISTS 
     -- is a standard relational-division solution] 
, msg_with_all_args AS (
    SELECT msgid FROM msg m 
    WHERE NOT EXISTS (
     SELECT * FROM tag t 
     WHERE EXISTS (SELECT * FROM args a WHERE a.tagid = t.tagid) 
     AND NOT EXISTS (
      SELECT * FROM msg_tag mt 
      WHERE mt.msgid = m.msgid 
      AND mt.tagid = t.tagid 
      ) 
     ) 
    ) 
     -- additional tags, associated with 
     -- messages with all tags 
, more_tags AS (
    SELECT * FROM tag t 
    WHERE EXISTS (
     SELECT * 
     FROM msg_tag mt 
     JOIN msg_with_all_args at ON at.msgid = mt.msgid 
     AND mt.tagid = t.tagid 
     ) 
     -- exclude the tags that are already in the set 
    AND NOT EXISTS (SELECT * FROM args nx where nx.tagid = t.tagid) 
    ) 
SELECT * FROM more_tags 
    ;