在一对多协会的条款

时间:2016-02-17 00:51:22

标签: sql postgresql join

我有两张表ProductsProductProperties

Products
  name - string
  description - text
  etc etc

ProductProperties
  product_id - integer
  property_id - integer

还有一个表Properties,它基本上存储了属性名称及其属性列表

如何实现一个SQL命令,用于查找具有property_ids(A或B或C)AND(X或Y或Z)的产品

我已经到了这里:

SELECT  DISTINCT "products".* 
FROM "products" 
INNER JOIN "product_properties" ON "product_properties"."product_id" = "products"."id" AND "product_properties"."deleted_at" IS NULL 
WHERE "products"."deleted_at" IS NULL 
AND (product_properties.property_id IN ('504, 506, 403')) 
AND (product_properties.property_id IN ('520, 501, 502'))

但它并没有真正起作用,因为它正在寻找一个既有值504也有520的产品属性,它永远不会存在。

非常感谢一些帮助!

3 个答案:

答案 0 :(得分:2)

您需要在属性组的基础上定义中间结果集:

SELECT DISTINCT p.* 
FROM products p
JOIN product_properties groupA ON groupA.product_id = p.id AND groupA.deleted_at IS NULL AND groupA.property_id IN ('504') 
JOIN product_properties groupB ON groupB.product_id = p.id AND groupB.deleted_at IS NULL AND groupB.property_id IN ('520')
WHERE p.deleted_at IS NULL 

你知道,你自己很好地发现了这个问题:"但它并没有真正起作用,因为它正在寻找一个既有504又有520的产品属性,它永远不会存在"

实际上,记录集在查询中是不可变的,应用于它们的所有单个条件都是一次性应用的。您需要复制每个表并对其应用单独的条件。

答案 1 :(得分:0)

一种方法使用existsin

select p.*
from products p
where p.id in (select pp.product_id
               from product_properties pp
               where pp.propertyid in ('504', '520')
              );

这使您不必在外部查询中使用distinct

如果,实际上,您的意思是找到所有属性的产品,那么joingroup by工作:

select p.*
from products p join
     product_properties pp
     on p.id = pp.product_id
where pp.propertyid in ('504', '520')
group by p.id -- yes, this is allowed in Postgres
having count(*) = 2;

答案 2 :(得分:0)

嗨试试这个查询我只是想着它所以我没有尝试任何一个检查我有想法我想做

SELECT  DISTINCT "products".* 
FROM products pr
WHERE  id IN
(
    SELECT product_id FROM ProductProperties WHERE property_id IN (504,520)
    GROUP BY product_id
    HAVING Count(*) = 2
) AND "products"."deleted_at" IS NULL 

SELECT  DISTINCT "products".* 
FROM products pr,  INNER JOIN (
    SELECT product_id,count(*) as nbr FROM ProductProperties WHERE property_id IN (504,520)
    GROUP BY product_id
) as temp ON temp.product_id = pr.id
WHERE "products"."deleted_at" IS NULL  AND temp.nbr = 2

并且您也可以检查这个(您也可以使用where子句中的连接而不是使用INNER JOIN)

SELECT  DISTINCT products.* FROM products as p 
INNER JOIN product_properties as p1 ON p1.product_id = p.id 
INNER JOIN product_properties as p2 ON p2.product_id = p.id 
WHERE p.deleted_at IS NULL 
AND p1.property_id = '504' AND p1.deleted_at IS NULL
AND p2.property_id = '520' AND p2.deleted_at IS NULL