使用多个AND和OR条件查询连接表

时间:2014-04-03 13:31:06

标签: ruby-on-rails postgresql activerecord ruby-on-rails-4 arel

我需要在Rails中构建一个返回具有一组特定属性的人的查询。我简化了我的榜样。所以这是两个表:

Table: people
+----+----------+
| id |   name   |
+----+----------+
|  1 | Person A |
|  2 | Person B |
|  3 | Person C |
+----+----------+

Table: attributes
+----+-----------+--------+--------+
| id | person_id |  name  | value  |
+----+-----------+--------+--------+
|  1 |         1 | age    | 32     |
|  2 |         1 | gender | male   |
|  3 |         2 | age    | 16     |
|  4 |         2 | gender | male   |
|  5 |         3 | gender | female |
+----+-----------+--------+--------+

person_id是对表people中某人的引用。

在我的查询中,我想(例如)提出以下问题:

  1. 给我所有年龄超过25岁的男性!

    name = 'gender' AND value = 'male'name = 'age' AND value > '25'应返回1条记录(person_id=1)

  2. 给我所有男性或25岁以上的人!

    name = 'gender' AND value = 'female'name = 'age' AND value > '25'应返回2条记录(person_id=1 and 3)

  3. 示例2并不那么难。但我在示例1中遇到了问题。我不知道如何在这里处理AND。不要忘记:WHERE语句是动态的。意味着可以有一堆,或只有一个。

    基本上我正在寻找合适的SQL语句来做到这一点。我已经玩了一点点,直到现在我做的最好的事情就是:

    SELECT people.* 
    FROM people 
    INNER JOIN attributes ON attributes.person_id = people.id 
    WHERE
      attributes.name = 'gender' AND attributes.value = 'male' OR 
      attributes.name = 'age' AND attributes.value > '25' 
    GROUP BY people.id 
    HAVING count(*) = 2
    

    我不喜欢这个解决方案,因为我必须在HAVING子句中指定匹配数。必须有一个更优雅和灵活的解决方案来做到这一点。

    这是一个不复杂的例子:

    SELECT people.* 
    FROM people 
    INNER JOIN attributes ON attributes.person_id = people.id 
    WHERE
      (attributes.name = 'gender' AND attributes.value = 'male') OR 
      (attributes.name = 'age' AND attributes.value > '25') AND
      (attributes.name = 'bodysize' AND attributes.value > '180')
    GROUP BY people.id
    

    任何想法和帮助将不胜感激。谢谢!

2 个答案:

答案 0 :(得分:1)

考虑类似

的内容
SELECT people.* 
FROM people
LEFT JOIN attributes AS attr_gender
    ON attr_gender.person_id = people.id 
    AND attr_gender.name = 'gender'
LEFT JOIN attributes AS attr_age
    ON attr_age.person_id = people.id 
    AND attr_age.name = 'age'

结合:

1)

SELECT ...
WHERE attr_gender.value = 'male'
AND attr_age.value::int > 25

2)

SELECT ...
WHERE attr_gender.value = 'male'
OR attr_age.value::int > 25

注意:必须进行投射 - '9' > '25'

答案 1 :(得分:0)

你试过这个:

  

(attributes.name ='gender'AND attributes.value ='male')或
  (attributes.name ='age'AND attributes.value> '25')

没有“GROUP BY”/“HAVING”部分?