2014-12-05 86 views
1

,我有以下數據:簡化和/或優化與INTERSECT SQL查詢或HAVING

tag_id | taggable_id 
--------+------------- 
     1 |   1 
     2 |   1 
     3 |   1 
     4 |   1 
     1 |   2 
     2 |   2 
     5 |   2 
     6 |   2 
     7 |   3 
     8 |   3 
     9 |   3 
    10 |   3 

而且我希望把所有這一切都是在一組tag_ids的,而在另一個組和另一個taggable_ids .. (最多4組)。
例如:

  • 如果我搜索所有與TAG_ID 1或7 AND TAG_ID的taggable_ids 4應該返回僅有1
  • 如果我搜索所有與TAG_ID 1 taggable_ids AND TAG_ID 6和TAG_ID 2或8應返回僅有2
  • 如果我搜索所有TAG_ID 8 taggable_ids和TAG_ID 5不應該返回IDS

在一個總的方式(對第二個例子),查詢如下:

SELECT taggable_id FROM taggings WHERE tag_id in (1) 
INTERSECT 
SELECT taggable_id FROM taggings WHERE tag_id in (6) 
INTERSECT 
SELECT taggable_id FROM taggings WHERE tag_id in (2,8) 

我想簡化它,它看起來像:

SELECT taggable_id FROM taggings WHERE tag_id in (1,2,6,8) 
GROUP BY taggable_id HAVING COUNT(*)=3 

,但我不知道是否能以更簡單的方式來完成。有什麼想法嗎?

+0

你的第二個查詢看起來很簡單。 – 2014-12-05 19:17:56

+0

'(tag_id,taggable_id)'被定義爲唯一的,對吧? – 2014-12-05 21:49:47

+0

您的查詢與您的描述不符。而你的第二個是*不等於第一個。提出一個一致的例子將是謹慎的。 – 2014-12-05 22:23:21

回答

2

這可以鑄成的relational division的情況下。我們已經按照此相關的問題組裝的查詢技術的阿森納:

根據數據分佈等因素的影響,這可能是最快的:

SELECT DISTINCT taggable_id 
FROM taggings t1 
JOIN taggings t2 USING (taggable_id) 
JOIN taggings t3 USING (taggable_id) 
WHERE t1.tag_id = 1 
AND t2.tag_id = 6 
AND t3.tag_id IN (2, 8); 

假設獨特(tag_id, taggable_id),示例中實際不需要DISTINCT。但是對於其他(列表)謂詞可能是必需的。

SQL Fiddle(建立在@ Clodoaldo的,謝謝)。

1

您的第二個查詢不等同於第一個查詢。在having條款改爲:

HAVING SUM(CASE WHEN tag_id = 1 THEN 1 ELSE 0 END) > 0 AND 
     SUM(CASE WHEN tag_id = 6 THEN 1 ELSE 0 END) > 0 AND 
     SUM(CASE WHEN tag_id IN (2, 8) THEN 1 ELSE 0 END) > 0; 

至於性能,測試了查詢,看看哪個效果更好。 having方法的優點是您可以添加越來越複雜的條件,而不會對性能產生重大影響。如果元組(8, 2)插入

2

SQL Fiddle

你的第二個查詢失敗。這裏是一個解決方案,雖然我不知道,如果簡單那麼intersect一個:

select taggable_id 
from taggings 
where tag_id in (1,2,6,8) 
group by taggable_id 
having 
    array_agg(tag_id) @> array[1,2] 
    and 
    array_agg(tag_id) && array[6,8]