I'm working on a SQL Query to join multiple rows of the same table and select the relevant columns (only NOT NULL columns). Here's what you have to know about my tables:
What I am trying to achieve is retrieve all products with all their attributes (named). To illustrate, if I have 2 attributes named "attribute_1" and "attribute_2", the final result shoud look like this:
{
"id" => 1,
"attribute_1" => "The attribute value", //The attribute value can be stored in any column suffixed by "_value"
"attribute_2" => "The attribute value" //The attribute value can be stored in any column suffixed by "_value"
}
I'm working with Laravel and ATM, here's what I'm doing:
//First retrieve all attribute names
$attribute_names = Attribute::select('name')->pluck('name');
//Build the final select statement that will be used
foreach ($attribute_names as $attribute_name) {
$select_array[] = DB::raw("MAX(CASE WHEN name='" . $attribute_name . "' THEN value ELSE NULL END) as " . $attribute_name);
}
//Sub query to select only the right column (the one that is not NULL)
$sub_query_select_only_not_null_columns = DB::table('attributes')
->leftJoin('product_attribute_values', 'product_attribute_values.attribute_id', 'attributes.id')
->select(
DB::raw('CASE
WHEN text_value IS NOT NULL THEN text_value
WHEN boolean_value IS NOT NULL THEN boolean_value
WHEN integer_value IS NOT NULL THEN integer_value
WHEN float_value IS NOT NULL THEN float_value
WHEN datetime_value IS NOT NULL THEN datetime_value
WHEN date_value IS NOT NULL THEN date_value
WHEN json_value IS NOT NULL THEN json_value
END AS value
'),
'attributes.name',
'product_attribute_values.product_id as product_id'
);
//Final query
Products::leftJoin('products', 'product_flat.product_id', '=', 'products.id') //Ignore this join
->leftJoinSub($testsub, 'mysubquery', function ($join) {
$join->on('products.id', '=', 'mysubquery.product_id');
})->select($select_array)->groupBy('products.id')
This query is working but there are some problems:
So here are my questions:
The problem is a bit complex to explain/understand. I can provide some more informations if you need. PS: I didn't provide the SQL because the query is a bit long, but I can share it.
Thanks in advance !
Product
and Attribute
using ProductAttributeValue
as a pivot model# Product model
public function attributes()
{
return $this->belongsToMany(Attribute::class, 'product_attribute_values', 'product_id', 'attribute_id')
->withPivot('text_value', 'boolean_value', ..., 'json_value')
->using(ProductAttributeValue::class);
}
ProductAttributeValue
model# ProductAttributeValue model
public function getValueAttribute()
{
return $this->text_value
?? $this->boolean_value
?? ...
?? $this->json_value;
}
$product = Product::with('attributes')->find(1);
$result = json_encode(
array_merge(
['id' => $product->id],
$product->attributes
->mapWithKeys(fn($attribute) => [$attribute->name => $attribute->pivot->value])
->toArray()
)
);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.