mysql 过滤具有多个条件的EAV表

hi3rlvi2  于 2024-01-05  发布在  Mysql
关注(0)|答案(3)|浏览(138)

我有两张table:
objects

  1. object_id | object_group_id

字符串
attributes

  1. attr_id | attr_object_id | attr_property_id | attr_value


现在,我想得到所有的object_id,其中object_group_id = 1和过滤器两个属性:

  1. (attr_property_id = 1 AND attr_value <= '100000')
  2. AND
  3. (attr_property_id = 2 AND attr_value > '2000')


我试着构造一些查询,像这样:

  1. SELECT * FROM objects as o
  2. /* filter1 join */
  3. INNER JOIN
  4. attributes AS f1
  5. ON
  6. o.object_id = f1.attr_object_id
  7. AND
  8. f1.attr_property_id = 1
  9. /* filter2 join */
  10. INNER JOIN
  11. attributes AS f2
  12. ON
  13. f1.attr_object_id = f2.attr_object_id
  14. AND
  15. f2.attr_property_id = 2
  16. WHERE
  17. o.object_group_id = 1
  18. AND
  19. f1.attr_value <= '100000'
  20. AND
  21. f2.attr_value > '2000'


……但还是得不到我想要的。

pbwdgjma

pbwdgjma1#

经过几个小时的组合和尝试,我终于做到了:

  1. SELECT * FROM objects as o
  2. /* filter1 join */
  3. INNER JOIN
  4. attributes AS f1
  5. ON
  6. o.object_id = f1.attr_object_id
  7. AND
  8. f1.attr_property_id = 1
  9. AND
  10. f1.attr_value <= '100000'
  11. /* filter2 join */
  12. INNER JOIN
  13. attributes AS f2
  14. ON
  15. f1.attr_object_id = f2.attr_object_id
  16. AND
  17. f2.attr_property_id = 2
  18. AND
  19. f2.attr_value > '2000'
  20. WHERE
  21. o.object_group_id = 1

字符串
我太接近了,并通过将所有过滤条件移动到INNER JOIN来完成这一点。

展开查看全部
hwamh0ep

hwamh0ep2#

我提出了一个替代的,可能更容易理解的方法。让我们在一个简单的例子中一步一步地看这个问题。我们的初始表可以有以下数据:

  • objects* table:
  1. object_id | object_group_id
  2. 1 1
  3. 2 1
  4. 3 1
  5. 4 2
  6. 5 1
  7. 6 1

字符串

  • attributes* table:
  1. attr_id | attr_object_id | attr_property_id | attr_value
  2. 1 1 1 50000
  3. 2 1 1 75000
  4. 3 1 1 150000
  5. 4 1 2 1000
  6. 5 1 2 5000
  7. 6 2 1 30000
  8. 7 2 1 200000
  9. 8 2 2 7000
  10. 9 3 1 500000
  11. 10 3 2 1000
  12. 11 4 1 90000
  13. 12 4 2 6000
  14. 13 5 1 150000
  15. 14 5 2 3000
  16. 15 6 1 70000
  17. 16 6 2 1000


I.我们开始处理第二个表,因为问题的主要部分实际上在其中,我们直接应用我们的过滤器:

  1. SELECT * from attributes
  2. WHERE (attr_property_id = 1 AND attr_value <= 100000) OR (attr_property_id = 2 AND attr_value > 2000)


请注意,我们在条件之间使用“OR”,因为我们需要从 attributes 表中获取适用于 * 一个 * OR * 另一个 * 条件的所有行
结果如下:

  1. attr_id | attr_object_id | attr_property_id | attr_value
  2. 1 1 1 50000
  3. 2 1 1 75000
  4. 5 1 2 5000
  5. 6 2 1 30000
  6. 8 2 2 7000
  7. 11 4 1 90000
  8. 12 4 2 6000
  9. 14 5 2 3000
  10. 15 6 1 70000


II.现在我们只需要取上面结果中 attr_property_id 为“1”和“2”的那些 * attr_object_id*,即那些 attr_object_id 符合我们最初问题的过滤器。我们可以通过以下查询来实现:

  1. SELECT attr_object_id, count(distinct(attr_property_id)) FROM attributes
  2. WHERE (attr_property_id = 1 AND attr_value <= 100000) OR (attr_property_id = 2 AND attr_value > 2000)
  3. GROUP BY attr_object_id


其结果是:

  1. attr_object_id | count
  2. 1 2
  3. 2 2
  4. 4 2
  5. 5 1
  6. 6 1


从上面的结果可以看出,attr_object_id 中的“1”、“2”和“4”都满足我们最初问题的过滤器,但“5”和“6”只是其中一个过滤器。现在让我们过滤掉“5”和“6”:

  1. SELECT attr_object_id FROM attributes
  2. WHERE (attr_property_id = 1 AND attr_value <= 100000) OR (attr_property_id = 2 AND attr_value > 2000)
  3. GROUP BY attr_object_id
  4. HAVING count(distinct(attr_property_id)) = 2


我们得到:

  1. attr_object_id
  2. 1
  3. 2
  4. 4


III.至此,问题的主要部分已经解决,我们只需要从 objects 表中应用过滤器,即 object_group_id = 1。这一个的查询很简单,我们只需要INNER JOIN objectsattributes 表,并在WHERE子句中添加一个条件:

  1. SELECT attr_object_id FROM attributes
  2. INNER JOIN objects on attributes.attr_object_id = objects.object_id
  3. WHERE object_group_id = 1 AND ((attr_property_id = 1 AND attr_value <= 100000) OR (attr_property_id = 2 AND attr_value > 2000))
  4. GROUP BY attr_object_id
  5. HAVING count(distinct(attr_property_id)) = 2


我们的例子的最终结果是:

  1. attr_object_id
  2. 1
  3. 2

展开查看全部
wnvonmuf

wnvonmuf3#

试试这个,我不知道你为什么会有最后几句

  1. SELECT
  2. o.object_id, o.object_group_id,
  3. f1.attr_value AS val1,
  4. f2.attr_value AS val2,
  5. FROM objects AS o
  6. LEFT JOIN attributes f1 ON o.object_id = f1.attr_object_id AND f1.attr_property_id = 1
  7. LEFT JOIN attributes f1 ON o.object_id = f2.attr_object_id AND f2.attr_property_id = 2
  8. WHERE
  9. o.object_group_id = 1
  10. AND
  11. f1.attr_value <= '100000'
  12. AND
  13. f2.attr_value > '2000';

字符串
删除此行并测试它

  1. AND
  2. f1.attr_value <= '100000'
  3. AND
  4. f2.attr_value > '2000';

展开查看全部

相关问题