最聪明的方式来编写“项目具有属性A,B,C但不具有X,Y,Z”查询

时间:2009-10-07 20:55:19

标签: sql mysql

好吧,假设我有这两个表:

  • 具有列ID,内容
  • 的项目
  • item_properties,包含列item_id,prop_id

现在我想执行像

这样的查询
SELECT stuff FROM items WHERE
      EXISTS(SELECT * FROM item_properties WHERE prop_id = 123 AND item_id = items.id)
  AND EXISTS(SELECT * FROM item_properties WHERE prop_id = 456 AND item_id = items.id)
  AND NOT EXISTS(SELECT * FROM item_properties WHERE prop_id = 789 AND item_id = items.id)
  AND NOT EXISTS(SELECT * FROM item_properties WHERE prop_id = 101 AND item_id = items.id)

哪个有效,但看起来很丑,很慢。谁能想到一个更聪明的方法呢?如有必要,我还可以通过第三个表中的子查询获取123,456和789,101列表。我也乐于接受改变我的桌面设计的建议。

检查项目属性所需的属性ID数量可能会有所不同。

谢谢!

4 个答案:

答案 0 :(得分:2)

如果您的表格包含prop_id以包含和排除itemsIU (item_id, prop_id, include)

select distinct stuff 
  from items i
  join item_properties ip on i.id = ip.item_id
  join itemsIU iiu on ip.prop_id = iiu.prop_id
group by i.id
having sum(include) = (select count(1) 
                         from itemsIU iiu2 
                        where i.id = iiu2.item_id
                          and iiu2.include = 1)

您可以使用以下特定示例:

select distinct stuff 
  from items i
  join item_properties ip on i.id = ip.item_id
  join (          select 123 prop_id, 1 include
        union all select 456, 1
        union all select 789, 0
        union all select 101, 0) iiu on ip.prop_id = iiu.prop_id
group by i.id
having sum(include) = 2

答案 1 :(得分:1)

SELECT stuff 
FROM Items as i
INNER JOIN item_properties as ip ON i.id = ip.item_id
WHERE ip.prop_id IN (123, 456) AND ip.prop_id NOT IN (789, 101)

它没有被测试,但是我倾向于做很多事情。

如果我理解你的问题,它应该有用。

答案 2 :(得分:0)

SELECT 
  i.*
FROM 
  Items as i
  INNER JOIN item_properties as ip ON i.id = ip.item_id
WHERE 
   ip.prop_id IN (123, 456) 
   AND ip.prop_id NOT IN (789, 101)

答案 3 :(得分:-1)

恭喜你,你偶然发现了不使用EAV的一个很好的理由。 :)

你能做的最好的就是:

SELECT *
  FROM items
 WHERE id IN (SELECT id FROM item_properties WHERE prop_id in (123, 456))
   AND id NOT IN (SELECT id FROM item_properties WHERE prop_id in (789, 101))

当mysql获得子查询实现时,会发生一些优化(例如将其中一个子查询转换为JOIN)但是现在,它只会生成派生表,而这些表将无法扩展。