I need to create a guys database, guys can have one or more attributes, and each guy attribute has a specific meaning, it sounds easy, huh? ok, read on as the problem becomes impossible (5 days with her: s).
So, I create these 3 tables:
CREATE TABLE guy ( id int(11), name varchar(255) ); CREATE TABLE attribute ( id int(11), name varchar(255) );
with example data:
INSERT INTO attribute VALUES (1, 'age'), (2, 'dollars'), (3, 'candies'); INSERT INTO guy VALUES (1, 'John'), (2, 'Bob'); INSERT INTO _value VALUES (1, 1, 1, 12), (2, 1, 2, 15), (3, 1, 3, 3); INSERT INTO _value VALUES (4, 2, 1, 15), (5, 2, 2, 20), (6, 2, 3, 6);
and create this query:
SELECT g.name 'guy', a.name 'attribute', v._value 'value' FROM guy g JOIN _value v ON g.id = v.guy_id JOIN attribute a ON a.id = v.attribute_id;
which gives me this result:
+------+-----------+-------+ | guy | attribute | value | +------+-----------+-------+ | John | age | 12 | | John | dollars | 15 | | John | candies | 3 | | Bob | age | 15 | | Bob | dollars | 20 | | Bob | candies | 6 | +------+-----------+-------+
THIS IS A REAL PROBLEM:
Later my boss told me that he wants to filter the data using as many conditions as he wants in order to be able to group these conditions using "ands" and "ors", for example, he might want to make this crazy condition:
Get guys who are older than 10, have less than 18 dollars, have more than 2 candies and less than 10 candies, but regardless of whether the guys are exactly 15, this will translate this filter:
-- should return both John and Bob (age > 10 and dollars < 18 and candies > 2 and candies < 10) or (age = 15)
I have no problem creating a filter (for this I use jqgrid), the problem is that the attributes are not columns, but rows instead , and because of this I donβt know how to mix the query with the filter, I tried something like this :
SELECT g.name 'guy', a.name 'attribute', v._value 'value' FROM guy g JOIN _value v ON g.id = v.guy_id JOIN attribute a ON a.id = v.attribute_id GROUP BY guy HAVING ( (attribute = 'age' and value > 10) AND (attribute = 'dollars' and value < 18) AND (attribute = 'candies' and value > 2) AND (attribute = 'candies' and value < 10) ) OR ( (attribute = 'age' and value = 15) )
but only Bob returns: (and I have to get both John and Bob.
SO MUST MIX FILTER AND REQUEST?
Keep in mind that the number of attributes each guy has is the same for all guys, but you can add more attributes and other guys at any time, for example, if I want to add the βMarioβ guy, I would do:
-- we insert the guy Mario INSERT INTO guy VALUES (3, 'Mario'); -- with age = 5, dollars = 100 and candies = 1 INSERT INTO _value VALUES (7, 3, 1, 5), (8, 3, 2, 100), (9, 3, 3, 1);
And if I want to create the apples attribute, I would do:
-- we insert the attribute apples INSERT INTO attribute VALUES (4, 'apples'); -- we create a value for each guy new attribute, John as 7 apples, Bob has 3 and Mario has 8 INSERT INTO _value VALUES (10, 1, 4, 7), (11, 2, 4, 2), (12, 3, 4, 8);
and now I should be able to include conditions in apples in my request.
I hope I understand, thanks for all your time :)
Note. Maybe if there was a way to put all the attributes of the guys on the same line ?, something like this:
+------+-----------+-------+------+------------+--------+------+------------+--------+------+------------+--------+ | guy | attribute | value | guy | attribute | value | guy | attribute | value | guy | attribute | value | +------+-----------+-------+------+------------+--------+------+------------+--------+------+------------+--------+ | John | age | 12 | John | dollars | 15 | John | candies | 3 | John | apples | 7 | | Bob | age | 15 | Bob | dollars | 20 | Bob | candies | 6 | Bob | apples | 2 | | Mario| age | 5 | Mario| dollars | 100| Mario| candies | 1 | Mario| apples | 8 | +------+-----------+-------+------+------------+--------+------+------------+--------+------+------------+--------+
Note 2: @iim suggested (in this question: How to search in grouped columns in MySQL? (Also in Hibernate, if possible) ) that I could do a self-join for each attribute, and yes that might solve the problem, but performance issues can occur when guys have a lot of attributes (like 30 or more).
Note 3: I cannot change the database schema :(