I need to build a query in Rails that returns people that have a certain set of attributes. I simplfied my example. So here are the two tables:
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
is a reference to a person in table people
.
In my query I want to (for example) ask the following questions:
Get me all male people who are older than 25!
name = 'gender' AND value = 'male'
and name = 'age' AND value > '25'
should return 1 record (person_id=1)
Get me all male people or people who are older than 25!
name = 'gender' AND value = 'female'
or name = 'age' AND value > '25'
should return 2 records (person_id=1 and 3)
Example 2 is not so hard to do. But I have my problems with example 1. I don't know how to handle the AND
here. And not to forget: The WHERE
statements are dynamic. Means there can be heaps of them, or just one.
Basically I am looking for the right SQL statement to do this. I already played around a little bit and the best thing I got until now was this:
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
I don't like this solution because I have to specify the number of matches in the HAVING
clause. There must be a more elegant and flexible solution to do this.
Here is a more complex example that doesn't work:
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
Any ideas and help will be appreciated. Thanks!