MySQL:查询与另一个表具有给定关系集的所有记录

时间:2010-08-19 13:10:09

标签: mysql ruby-on-rails relational-database

是的,有点愚蠢的称号,但我发现很难描述我的问题。我有以下表格:

属性

id | name
1  | color
2  | material

选项

id | property_id | name
1  | 1           | yellow
2  | 1           | blue
3  | 2           | wood
4  | 2           | stone

物质

id | name
1  | orange juice
2  | cheese

关系

id | substance_id | option_id
1  | 2            | 1
2  | 2            | 3
3  | 1            | 1

现在,我有一个选项列表,想知道哪些物质与所有这些选项有关。 (例如,哪些物质是黄色的并且由木材制成?)这可以通过一个查询来实现吗?

我正在尝试在Rails中执行此操作。

3 个答案:

答案 0 :(得分:0)

刚出头,你可以试试:

SELECT DISTINCT s.name FROM substances s, relation r 
WHERE r.substance_id = s.id 
      AND r.option_id IN ( 1, 3) 

答案 1 :(得分:0)

(SELECT s.name FROM substances s, relations r, options o
WHERE r.substance_id = s.id and r.option_id = o.id and o.name='yellow')
INTERSECT
(SELECT s.name FROM substances s, relations r, options o
WHERE r.substance_id = s.id and r.option_id = o.id and o.name='wood')

或者

SELECT s.name FROM substances s
WHERE exists(SELECT * from relations r, options o 
      WHERE r.substance_id = s.id and r.option_id = o.id and o.name='yellow')
AND   exists(SELECT * from relations r, options o 
      WHERE r.substance_id = s.id and r.option_id = o.id and o.name='wood')

拥有一个options表与property_id来分辨不同类型的选项并不是一个好主意,真的让这更难。我建议将不同类型的选项分成不同的表格

MATERIALS(id,name)
COLORS(id,name)

并为每种类型的表使用单独的关系。在这种情况下,您不需要为每个关系使用单独的表,因为它似乎是一个(物质)到一个(颜色)关系。

SUBSTANCES(id, name, material_id, color_id)

然后您的查询更加简单

SELECT s.name FROM substances s, materials m, colors c
WHERE s.color_id = c.id AND m.material_id = m.id
AND m.name = 'wood'
AND c.name = 'yellow'

ActiveRecord应该能够比前两个更容易地处理这个最后一个查询。

答案 2 :(得分:0)

SELECT s.name
FROM   substances AS s
       LEFT JOIN relations AS r1
         ON s.id = r1.substance_id
       INNER JOIN relations AS r2
         ON r1.substance_id = r2.substance_id
            AND r1.option_id < r2.option_id
       LEFT JOIN options AS o1
         ON o1.id = r1.option_id
       LEFT JOIN options AS o2
         ON o2.id = r2.option_id
WHERE  o1.name = 'yellow'
       AND o2.name = 'wood'  

我不太了解优化SQL的性能。您可能希望对上面的这个(下面)以及此处发布的其他解决方案进行基准测试。

SELECT s.name
FROM   substances AS s
       LEFT JOIN relations AS r1
         ON s.id = r1.substance_id
       INNER JOIN relations AS r2
         ON r1.substance_id = r2.substance_id
            AND r1.option_id < r2.option_id
       LEFT JOIN options AS o1
         ON o1.id = r1.option_id
     AND o1.name = 'wood'
       LEFT JOIN options AS o2
         ON o2.id = r2.option_id
     AND o2.name = 'yellow'