在MySQL中搜索分组的列?

问题描述

下面的内容将使您或多或少地简化您的条件,尽管我不能保证拥有100,000多个具有30多个属性的人会非常有效。您应该自己看看。

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 (
    SUM(a.name = 'age'     and v._value > 10) = 1 AND
    SUM(a.name = 'dollars' and v._value < 18) = 1 AND
    SUM(a.name = 'candies' and v._value > 2 ) = 1 AND
    SUM(a.name = 'candies' and v._value < 10) = 1
       )
OR
       (
    SUM(a.name = 'age'     and v._value = 15) = 1
       )

(我在这里假设一个人不能有重复的属性。)

解决方法

我需要创建一个男生数据库,男生可以具有一个或多个属性,每个男生的属性都有特定的值,听起来容易吗?好吧,继续阅读,因为问题有点儿变得不可能了(5天:s)。

所以我创建了这3个表:

CREATE TABLE guy (
  id int(11),name varchar(255)
);

CREATE TABLE attribute (
  id int(11),name varchar(255)
);

-- each value references one guy and one attribute
CREATE TABLE _value (
  id int(11),guy_id int(11),attribute_id int(11),_value varchar(255)
);

使用此示例数据:

INSERT INTO attribute VALUES (1,'age'),(2,'dollars'),(3,'candies');
INSERT INTO guy VALUES (1,'John'),'Bob');
INSERT INTO _value VALUES (1,1,12),2,15),3,3);
INSERT INTO _value VALUES (4,(5,20),(6,6);

并创建此查询:

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;

这给了我这个结果:

+------+-----------+-------+
| guy  | attribute | value |
+------+-----------+-------+
| John | age       | 12    |
| John | dollars   | 15    |
| John | candies   | 3     |
| Bob  | age       | 15    |
| Bob  | dollars   | 20    |
| Bob  | candies   | 6     |
+------+-----------+-------+

这是真正的问题:

后来,我的老板告诉我他想使用尽可能多的条件来过滤数据,例如,他希望能够使用“ ands”和“ or”对这些条件进行分组,例如,他可能想执行以下疯狂条件:

取得年龄大于10岁,拥有少于18美元,拥有2个以上糖果和少于10个糖果的人,但是无论如何,还应包括年龄恰好为15岁的人。这将转换为以下过滤器:

-- should return both John and Bob
(age > 10 and dollars < 18 and candies > 2 and candies < 10) or (age = 15)

我没有问题创建过滤器(为此我使用jqgrid), 问题是属性不是列,而是行 ,因此,我不知道如何将查询与过滤器混合,我尝试了像这样的东西:

SELECT g.name 'guy',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)
       )

但只有鲍勃返回了:(我应该同时得到约翰和鲍勃。

因此,我应该如何混合过滤器和查询?

请记住,每个人拥有的属性数量对于所有人都是相同的,但是可以随时添加更多属性和更多人,例如,如果我想添加人“ Mario”,我会这样做:

-- we insert the guy Mario
INSERT INTO guy VALUES (3,'Mario');
-- with age = 5,dollars = 100 and candies = 1
INSERT INTO _value VALUES (7,5),(8,100),(9,1);

如果我想创建属性“ apples”,我会这样做:

-- we insert the attribute apples
INSERT INTO attribute VALUES (4,'apples');
-- we create a value for each guy's new attribute,John as 7 apples,Bob has 3 and Mario has 8
INSERT INTO _value VALUES (10,4,7),(11,2),(12,8);

现在我应该可以在查询中包含有关苹果的条件。

我希望自己能理解,谢谢您的所有时间:)

注意:也许是否有一种方法可以将每个人的所有属性都放在一行中?

+------+-----------+-------+------+------------+--------+------+------------+--------+------+------------+--------+
| 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 |
+------+-----------+-------+------+------------+--------+------+------------+--------+------+------------+--------+

注意2:@iim建议(在这个问题中:如何在MySQL的分组列中搜索?(如果可能,也在Hibernate中))我可以为每个属性进行自联接,是的,这可以解决问题,但是有当男人拥有大量属性(例如30个或更多)时,可能是性能问题。

注意3:我不能更改数据库架构:(