我的数据库中有3个表
# Items
id - name
----------
1 - Item A
2 - Item B
3 - Item C
# Traits
id - name
----------
1 - Color
2 - Grade
3 - Size
# Values
id - item_id - trait_id - value
----------
1 - 1 - 1 - red
1 - 2 - 1 - green
1 - 3 - 1 - red
1 - 1 - 2 - 90%
1 - 2 - 2 - 45%
1 - 3 - 2 - 80%
1 - 1 - 3 - 4 inches
1 - 2 - 3 - 5 inches
1 - 3 - 3 - 9 inches
在Laravel中,我可以使用" belongsTo"来获取所有具有其特征和价值的项目。 [$ this-> belongsTo(' App \ Traits',' trait_id');]在Value模型中获得如下结果:
--- Item A
Color: red
Grade: 90%
Size: 4 inches
--- Item B
Color: green
Grade: 45%
Size: 5 inches
.. etc
来自这样的代码:
$items = Items::get();
foreach ($items as $item) {
echo '<h2>'.$item->name.'</h2>';
foreach ($item->values as $value) {
echo '<b>'.$value->trait->name . '</b>: ';
echo $value->value . '<br>';
}
}
然而,我无法做的是我需要过滤这些结果,例如,我只需要其颜色为&#34;红色&#34;它的等级大于70%?
如果您不使用Larave,请随意在纯粹的mysql查询中编写它,当我得到这个想法时,我可能会在Laravel中找到一种方法...谢谢
答案 0 :(得分:1)
按(多个)属性 - 值对过滤项目/实体是EAV model的缺点之一。有一些方法可以实现这一目标。一种是每个条件加入Items
表格Traits
和Values
:
select i.*
from Items i
join `Values` v1 on v1.item_id = i.id
join `Values` v2 on v2.item_id = i.id
join Traits t1 on t1.id = v1.trait_id
join Traits t2 on t2.id = v2.trait_id
where t1.name = 'Color' and v1.value = 'red'
and t2.name = 'Grade' and v2.value > 70
您还可以使用旋转来获取列的结果(item_id,Color,Grade):
select v.item_id
, max(case when t.name = 'Color' then v.value end) as Color
, max(case when t.name = 'Grade' then v.value end) as Grade
from `Values` v
join Traits t on t.id = v.trait_id
group by v.item_id
having Color = 'red' and Grade > 70
此结果可以与Items
表连接以获取过滤的项目。修改也可以在WHERE-IN条件中使用:
select * from Items
where id in (
select v.item_id
from `Values` v
join Traits t on t.id = v.trait_id
group by v.item_id
having max(case when t.name = 'Color' then v.value end) = 'red'
and max(case when t.name = 'Grade' then v.value end) > 70
);
另一种方法:
select * from Items
where id in (
select v.item_id
from `Values` v
join Traits t on t.id = v.trait_id
where t.name = 'Color' and v.value = 'red'
or t.name = 'Grade' and v.value > 70
group by v.item_id
having count(v.item_id) = 2
);