使用多个条件过滤EAV表

问题描述 投票:0回答:3

我有2张桌子:

objects

object_id | object_group_id

attributes

attr_id | attr_object_id | attr_property_id | attr_value

现在,我想获取所有

object_id
其中
object_group_id = 1
并过滤两个属性:

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

我试图构建一些查询,如下所示:

SELECT * FROM objects as o

/* filter1 join */
INNER JOIN 
    attributes AS f1 
        ON 
    o.object_id = f1.attr_object_id 
        AND 
    f1.attr_property_id = 1

/* filter2 join */
INNER JOIN 
    attributes AS f2 
        ON 
    f1.attr_object_id = f2.attr_object_id 
        AND 
    f2.attr_property_id = 2

WHERE 
    o.object_group_id = 1
       AND
   f1.attr_value <= '100000'
       AND
   f2.attr_value > '2000'

...但仍然无法得到我需要的东西。

mysql sql entity-attribute-value
3个回答
4
投票

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

    SELECT * FROM objects as o

/* filter1 join */
INNER JOIN 
    attributes AS f1 
        ON 
    o.object_id = f1.attr_object_id 
        AND 
    f1.attr_property_id = 1
        AND
    f1.attr_value <= '100000'

/* filter2 join */
INNER JOIN 
    attributes AS f2 
        ON 
    f1.attr_object_id = f2.attr_object_id 
        AND 
    f2.attr_property_id = 2
        AND
    f2.attr_value > '2000'

WHERE 
    o.object_group_id = 1

我太接近了,并通过将所有过滤条件移至

INNER JOIN
来完成此操作。


0
投票

试试这个。我不知道为什么你有最后几行

SELECT
  o.object_id, o.object_group_id,
  f1.attr_value AS val1,
  f2.attr_value AS val2,
FROM objects AS o
LEFT JOIN attributes f1 ON o.object_id = f1.attr_object_id AND f1.attr_property_id = 1
LEFT JOIN attributes f1 ON o.object_id = f2.attr_object_id AND f2.attr_property_id = 2
WHERE
    o.object_group_id = 1
AND
   f1.attr_value <= '100000'
AND
   f2.attr_value > '2000';

删除此行并测试它

AND
   f1.attr_value <= '100000'
AND
   f2.attr_value > '2000';

0
投票

我想出了一种替代的、可能更容易理解的方法。 让我们通过一个简单的例子逐步来看这个问题。我们的初始表可以包含以下数据:

对象表:

object_id  |  object_group_id
    1                1
    2                1
    3                1
    4                2
    5                1
    6                1

属性表:

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

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

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

请注意,我们在条件之间使用“OR”,因为我们需要从 attributes 表中获取适用于 one OR another 条件

的所有行

结果如下:

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

二.现在我们只需要在上面的结果中取那些同时具有 attr_property_id “1”和“2”的 attr_object_id,即那些 attr_object_id 遵循我们最初问题的过滤器。我们可以通过以下查询来实现:

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

结果是:

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

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

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

我们得到:

attr_object_id
      1
      2
      4

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

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

我们示例的最终结果是:

attr_object_id
      1
      2
© www.soinside.com 2019 - 2024. All rights reserved.