[英]MySQL (Laravel Eloquent) - Get record when two columns have two or more values at the same time
我有从这篇文章中获得的用于管理产品及其变体的数据库:
+---------------+ +---------------+
| PRODUCTS |-----< PRODUCT_SKUS |
+---------------+ +---------------+
| #product_id | | #product_id |
| product_name | | #sku_id |
+---------------+ | sku |
| | price |
| +---------------+
| |
+-------^-------+ +------^------+
| OPTIONS |------< SKU_VALUES |
+---------------+ +-------------+
| #product_id | | #product_id |
| #option_id | | #sku_id |
| option_name | | #option_id |
+---------------+ | value_id |
| +------v------+
+-------^-------+ |
| OPTION_VALUES |-------------+
+---------------+
| #product_id |
| #option_id |
| #value_id |
| value_name |
+---------------+
问题是,当用户选择他想要的产品选项时,我不知道如何获得 SKU:
SKU_VALUES
==========
product_id sku_id option_id value_id
---------- ------ --------- --------
1 1 1 1 (W1SSCW; Size; Small)
1 1 2 1 (W1SSCW; Color; White)
1 2 1 1 (W1SSCB; Size; Small)
1 2 2 2 (W1SSCB; Color; Black)
假设用户选择了 ID 为 1 的产品以及选项 size-small 和 color-black,我如何获得sku_id
(在这种情况下,我希望sku_id
中的值 2 )以获得里面的价格PRODUCT_SKUS
表。
由于显而易见的原因,我不能做这样的事情:
SELECT sku_id FROM SKU_VALUES
WHERE (SKU_VALUES.option_id = 1 AND SKU_VALUES.value_id = 1)
AND (SKU_VALUES.option_id = 2 AND SKU_VALUES.value_id = 2)
请注意,我似乎需要 append 与产品可用选项数量相同的条件(或我需要的任何东西),在这种情况下只有 2 行,因为产品有 2 个选项(尺寸和颜色),但产品可能有“n”个选项。
如果有人可以指导我进行此查询,并且可以使用 Laravel Eloquent 而不是使用 RAW 查询,我将不胜感激。
我创建的模型如下:
“产品”Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Producto extends Model
{
protected $table = 'productos';
protected $fillable = [
'nombre',
'descripcion'
];
public function opciones(){
return $this->hasMany('App\Models\OpcionProducto', 'producto_id');
}
public function skus(){
return $this->hasMany('App\Models\ProductoSku', 'producto_id');
}
}
“选项”Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\HasCompositePrimaryKey;
class OpcionProducto extends Model
{
use HasCompositePrimaryKey;
protected $table = 'productos_opciones';
protected $primaryKey = array('producto_id', 'opcion_id');
protected $fillable = [
'producto_id',
'opcion_id',
'nombre_opcion',
'valor'
];
public function producto(){
return $this->belongsTo('App\Models\Producto', 'producto_id');
}
public function valores(){
return $this->hasMany('App\Models\OpcionValorProducto', 'opcion_id', 'opcion_id');
}
public function skusValores(){
return $this->hasMany('App\Models\SkuValor', 'opcion_id', 'opcion_id');
}
}
“选项值”Model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\HasCompositePrimaryKey;
class OpcionValorProducto extends Model
{
use HasCompositePrimaryKey;
protected $primaryKey = array('producto_id', 'opcion_id', 'valor_id');
protected $table = 'productos_opciones_valores';
protected $fillable = [
'producto_id',
'opcion_id',
'valor_id',
'valor_variacion',
'valor'
];
public function producto(){
return $this->belongsTo('App\Models\Producto', 'producto_id');
}
public function opcion(){
return $this->belongsTo('App\Models\OpcionProducto', 'opcion_id', 'opcion_id');
}
}
“产品_SKUS” model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\HasCompositePrimaryKey;
class ProductoSku extends Model
{
use HasCompositePrimaryKey;
protected $primaryKey = array('producto_id', 'sku_id');
protected $table = 'productos_skus';
protected $fillable = [
'producto_id',
'sku_id',
'imagen_id',
'precio',
'stock',
'sku'
];
public function producto(){
return $this->belongsTo('App\Models\Producto', 'producto_id');
}
public function valoresSku(){
return $this->hasMany('App\Models\SkuValor', 'sku_id');
}
}
}
“SKU_VALUES”model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\HasCompositePrimaryKey;
class SkuValor extends Model
{
use HasCompositePrimaryKey;
protected $primaryKey = array('producto_id', 'sku_id', 'opcion_id');
protected $table = 'valores_skus';
protected $fillable = [
'producto_id',
'sku_id',
'opcion_id',
'valor_id',
];
public function producto(){
return $this->belongsTo('App\Models\Producto', 'producto_id');
}
public function opcion(){
return $this->belongsTo('App\Models\OpcionProducto', 'opcion_id', 'opcion_id');
}
public function sku(){
return $this->belongsTo('App\Models\ProductoSku', 'sku_id', 'sku_id');
}
}
这是使用纯 SQL 的解决方案。
这是您使用原始查询的尝试:
select sku_id
from sku_values
where (option_id = 1 and value_id = 1) and (option_id = 2 and value_id = 2)
这不起作用,因为您需要在共享相同sku_id
的行之间进行搜索,而不是在每一行上进行搜索。 这建议聚合:
select sku_id
from sku_values
where (option_id, value_id) in ((1, 1), (2, 2)) -- either one combination or the other
group by sku_id
having count(*) = 2 -- both match
您可以通过在where
子句谓词中添加更多组合并相应地增加having
子句中的目标计数来轻松扩展查询以获得更多选项。 例如,这会根据 4 个条件进行过滤:
select sku_id
from sku_values
where (option_id, value_id) in ((1, 1), (2, 2), (3, 10) (12, 17))
group by sku_id
having count(*) = 4
也可以通过在子查询中添加更多连接来按选项名称和值进行过滤:
select sv.sku_id
from sku_values sv
inner join options o
on o.product_id = sv.product_id
and o.option_id = sv.option_id
inner join option_values ov
on ov.product_id = sv.product_id
and ov.option_id = sv.option_id
and ov.value_id = sv.value_id
where (o.option_name, ov.value_name) in (('Size', 'Small'), ('Color', 'Black'))
group by sv.sku_id
having count(*) = 2
现在,假设您要获取相应的产品名称和价格:您可以将上述查询与相关表连接起来。
select p.product_name, ps.price
from products p
inner join product_skus ps
on ps.product_id = p.product_id
inner join (
select sv.sku_id
from sku_values sv
inner join options o
on o.product_id = sv.product_id
and o.option_id = sv.option_id
inner join option_values ov
on ov.product_id = sv.product_id
and ov.option_id = sv.option_id
and ov.value_id = sv.value_id
where (o.option_name, ov.value_name) in (('Size', 'Small'), ('Color', 'Black'))
group by sv.sku_id
having count(*) = 2
) x
on x.sku_id = ps.sku_id
在完成您的问题后,这是我想出的代码。 当然,这是未经测试的。 请试一试。
$skuValor = SkuValor::with('producto', 'opcion.valores', 'sku')
->whereHas('producto', function ($q) use ($request) {
$q->where('id', $request->get('product_id')); // id: 1
})
->whereHas('opcion', function ($q) use ($request) {
$q->whereIn('id', $request->get('option_ids')) // id: [1, 2] where 1=size, 2=color
->whereHas('valores', function($q2) use ($request) {
$q2->whereIn('id', $request->get('value_ids')); // id: [1, 3] where 1=small, 3=pink
});
})
->get();
$skuValor->sku->id; // sky id
with()
:这称为Eager Loading 。 在检索 model 时加载一些关系。
whereHas()
: 查询关系是否存在。 此方法允许您将自定义约束添加到关系约束。
use()
:传递数据以便内部(特定)查询可以使用它。 请注意,我们将 1 用于 opcion,将另一个用于 valores。
whereIn()
:此方法验证给定列的值是否包含在给定数组中。
如果您遇到困难,请发表评论。
这可以使用 Laravel子查询来实现,但我建议使用创建一个 RAW 查询来获取您需要的那些值,然后使用 Laravel 查询构建器来实现它。
对于涉及许多表的查询 Eloquent 可能会导致某种效率低下,并且会导致您编写无法维护的代码。
额外的建议,即使您的表名是其他语言,也建议创建完整的英文模型,您可以指定哪些字段与哪些属性相关。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.