Laravel5: Eloquent and JOIN - mysql

Items Table
| id | item_id | item_title |
|-------|---------|------------|
| 1 | 1002 | A |
| 2 | 1003 | B |
| 3 | 1004 | C |
Sells Table
| id | item_id |
|----|-----------|
| 1 | 1002 1003 |
| 2 | 1003 1004 |
| 3 | 1004 1002 |
I want result : Sells Table 1. item title is A B
I want to combine the sells table with the item table and then match the item_id of the sells table to the item_title of the item table.

The table definitions look incorrect, you should have a pivot table linking items with sells, so a sell_item table:
item_id | sell_id
-----------------
1 | 1
1 | 3
2 | 1
2 | 2
3 | 2
3 | 3
Then using eloquent, you'd create models to represent your tables and define the relationships using BelongsToMany:
class Item extends Model {
public function sells() {
return $this->belongsToMany(Sell::class);
}
}
class Sell extends Model {
public function items() {
return $this->belongsToMany(Item::class);
}
}
Each instance of either model will then have access to it's related models via $item->sells and $sell->items.
The query builder can perform a join if not going the Eloquent route:
DB::table('sells')->join('items', 'sells.item_id', '=', 'items.item_id')
->select('sells.*', 'items.title')
->get();

The table definitions look incorrect, If you corrected already then your model replationship should be like
class Item extends Model {
public function sells() {
return $this->belongsToMany(Sell::class);
}
}
class Sell extends Model {
public function items() {
return $this->belongsToMany(Item::class);
}
}
Each instance of either model will then have access to it's related models via $item->sells and $sell->items.
The query builder can perform a join if not going the Eloquent route:
DB::table('sells')->join('items', 'sells.item_id', '=', 'items.item_id')
->select('sells.*', 'items.title')
->get();
Or if your model name is Sell then
$response=Sell::with('items')->get();

Related

How to multiply and group using laravel eloquent with relation

I'd like to export data from my database but have problems with multiplying and sum using laravel eloquent with relation
So i have 2 tables there (budgets, items)
Budget's:
// Table
+----+---------------+-----------------+------+-----+--------------------+
| id | delivery_plan | item_code | curr | qty | price |
+----+---------------+-----------------+------+-----+--------------------+
| 1 | 2022-08 | 201.0001 | IDR | 1 | 2000.0000000000 |
| 2 | 2022-08 | 201.0001 | IDR | 3 | 2000.0000000000 |
| 3 | 2022-07 | 201.9999 | IDR | 2 | 2000.0000000000 |
+----+---------------+-----------------+------+-----+--------------------+
// Relation
public function item()
{
return $this->belongsTo(Item::class, 'item_code', 'item_code');
}
Items :
// Table
+----+----------------+-----------+
| id | subgroup | item_code |
+----+----------------+-----------+
| 1 | KOMPONEN MESIN | 201.0001 |
| 2 | EQUIPMENT LAIN | 201.9999 |
+----+----------------+-----------+
// Relation
public function budgets()
{
return $this->hasMany(Budget::class, 'item_code', 'item_code');
}
So, the scenario is :
Multiply the "qty" * "price" columns and name them as "total" like so
Group them by "subgroup" column, which came from item() relationship
Group them by "delivery_plan"
I prefer using eloquent because to minimize the complexity because i need that "whereHas" method
This is what i've tried so far and isn't working :
$budgets = Budget::with('item', 'rate')->whereHas('period.term', function (Builder $builder) {
$builder->where('name', '=', Session::get('term-budget'));
})->where('section', Session::get('section-budget'))->getQuery();
$result = $budgets->sum('price * qty')->get();
How can i achieve this ?
This can be solved by a join with SUM(), something like below (untested):
Budget::leftJoin('items', 'budgets.item_code', '=', 'items.item_code')
->addSelect('subgroup')
->addSelect('delivery_plan')
->addselect(\DB::raw('SUM(qty * price) as total'))
->groupBy('subgroup', 'delivery_plan')
->get();

Laravel Eloquent select distinct from relationship

I have a many to many relationship between categories and products tables.
┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ categories │ │ products │ │ category_product │
├─────────────────┤ ├─────────────────┤ ├──────────────────┤
| id | | id | | shop_id |
| name | | name | | category_id |
| created_at | | price | | product_id |
└─────────────────┘ | created_at | | created_at |
└─────────────────┘ └──────────────────┘
Category model:
class Category extends Model
{
public function products()
{
return $this->belongsToMany(Product::class);
}
}
Product model:
class Product extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
Because I'm using the cetegory_product table to also map the shop. I have some problem with getting the distinct results. let's just say that I have the following records in the pivot table:
shop_id | category_id | product_id
--------------------------------------
1 |18 |4
1 |18 |5
Now when I try to get the categories for a shop or the reverse relationship like this:
$shop = Shop::find(1);
$shop->categories()->get();
I get duplicated data.
So I like to know how can I perform a distinct select for categories?
BTW: I tried to add a scope on each model, adding the distinct to the query, but it did not work.
Unless I'm missing something you should be able to use groupBy().
$shop = Shop::find(1);
$shop->categories()->groupBy('category_id')->get();
$shop->categories()->distinct()->get();

How to calculate results in multiple tables with Eloquent ORM

I'm start learning MySQL and have some problem with selecting and calculating im multiple tables.
I have 2 tables:
First table "places"
id | name |
1 | restaurant |
Second table "ratings"
id | expert | place_id | design | personal | cooking
1 | expert 1 | 1 | 5 | 5 | 4
2 | expert 2 | 1 | 3 | 3 | 3
3 | expert 3 | 1 | 4 | 2 | 3
I select places with
$places = Place::all();
and used it
return view('place',compact('places'));
I need to use data from "rating" table with "places" and don't know how to do that
I need to find average of all values and average of each type of value AND use it with places.
How can I do this?
Asuming you're using atleast Laravel 5 you can make a has many relationship in your Place model.
Here is an example taken from the docs:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Place extends Model
{
/**
* Get the comments for the blog post.
*/
public function comments()
{
return $this->hasMany('App\Rating');
}
}

Loading a polymorphic model recursive with conditions

I try to eager load a polymorphic model with some conditions that's connected to two other models and having some problems.
My models:
class One extends Model {
public function twos() {
return $this->hasMany(Two::class);
}
public function threes() {
return $this->morphMany(Three::class, 'threeable');
}
}
class Two extends Model {
public function one() {
return $this->belongsTo(One::class);
}
public function threes() {
return $this->morphMany(Three::class, 'threeable');
}
}
class Three extends Model {
public function threeable() {
return $this->morphTo();
}
}
So far everythings is everything great: I've a lot of One items that have a lot of Two relations and both have even more Three relations (on its own).
Now I try to get the latest Three from Two, where it also can come from a One relation (highest threes.updated_at from either A or B).
The threes table looks something like this
| id | threeable_id | threeable_type | updated_at |
|---|---|---|---|
| 1 | 1 | A | 1 |
| 2 | 1 | A | 2 |
| 3 | 1 | B | 3 |
| 4 | 1 | B | 4 |
| 5 | 2 | A | 2 |
| 6 | 2 | A | 4 |
| 7 | 2 | B | 1 |
| 8 | 2 | B | 3 |
I want threes.id = 4 for B::find(1)->withC() and threes.id = 6 for B::find(2)->withC().
For performance reasons I want to load it in one query (I'm loading multiple Two and want the related Three and don't want to fire an own query for that). So I tried to put it in a scope (in class Two). Joining on the Three table and doing some max on the updated_at in a sub query ... It was a total mess and didn't worked that well
It didn't really feel the "Laravel-way" neither :(
Thanks for any help
EDIT
Maybe as an addition here's the pure SQL
SELECT twos.id, threes.id
FROM
(SELECT
twos.id twoId, MAX(th.updated_at) threeMaxUA
FROM
twos
LEFT JOIN (SELECT
th.*
FROM
(SELECT
threeable_id, threeable_type, MAX(updated_at) AS updated_at
FROM
threes
WHERE
deleted_at IS NULL
GROUP BY threeable_id , threeable_type) thmax
LEFT JOIN
threes pr ON (th.threeable_id = thmax.threeable_id
AND th.updated_at = thmax.updated_at
AND th.threeable_type = thmax.threeable_type)
GROUP BY th.threeable_id , th.threeable_type) th
ON
(
(th.threeable_id = twos.id AND th.threeable_type = 'App\\Two')
OR
(th.threeable_id = twos.product_id AND th.threeable_type = 'App\\One')
)
GROUP BY twos.id
) twthmax
LEFT JOIN twos ON twos.id = twthmax.twoId
LEFT JOIN threes ON (
twthmax.threeMaxUA = threes.updated_at
AND
(
(threes.threeable_id = twos.id AND threes.threeable_type = 'App\\Two')
OR
(threes.threeable_id = twos.product_id AND threes.threeable_type = 'App\\One')
)
)

Laravel query builder doesn't return all prices based on role = customer. Just return 1 price

I'm designing an application where a retailer can add a product with an initial price (store in a products table shown as example), then customers can claim the price of the product purchased from the retailer (this information stores in the prices table shown as example). The retailer then can update / reclaim the price inside the prices table too. and customers can reclaim the price of the product over and over again.
So, I have 2 roles of users called retailer and customer. I'm using Entrust Role package with the default relationship between role and user in the model. Before I explain next, here is my simple database design with all working example (feel free to ask for anything to include):
=============== MY Database Design with sample ===============
table users
__________________________
| id | email | password |
|-------------------------|
| 1 | a#g.com | 123 |
| 2 | b#g.com | 123 |
| 3 c#g.com | 123 |
| 4 d#g.com | 123 |
--------------------------
table roles
______________
|id | slug |
|--------------|
|1 | customer |
|2 | retailer |
----------------
table role_user
__________________
|id_user | id_role|
|------------------|
| 1 | 1 | -> a#gmail.com is a customer
| 2 | 2 | -> b#gmail.com is a retailer
| 3 | 1 | -> c#gmail.com is a customer
| 4 | 1 | -> d#gmail.com is a customer
------------------
table price:
(customer or retailer can claim 1 or more prices):
_____________________________________
|id| user_id | product_id | price |
|----------------------------|
|1 | 1 | 1 |10.00 | -> price claimed by a customer a#gmail.com on product 1
|2 | 2 | 1 |5.00 | -> price claimed by a retailer b#gmail.com on product 1
|3 | 1 | 1 |6.00 | -> price claimed by a previous customer a#gmail.com on product 1
|4 | 3 | 1 |5.00 | -> price claimed by a customer c#gmail.com on product 1
|5 | 2 | 1 |7.00 | -> price claimed by a previous retailer b#gmail.com on product 1
|6 | 3 | 1 |8.00 | -> price claimed by a customer c#gmail.com on product 1
Table products
_____________________________________
|id | user_id| name | Price
|-------------------------------------
| 1 | 1 | Milk | 10.00
| 2 | 2 | Phone | 12.33
| 3 | 1 | computer | 33.44
| 4 | 1 | Banana | 33.22
--------------------------------------
=============== MY Model Relationship ===============
Price model relationship
class Price extends Model
{
public function product()
{
return $this->belongsTo('App\Product');
}
public function user()
{
return $this->belongsTo('App\User');
}
}
Product model relationship
class Product extends Model
{
public function prices()
{
return $this->hasMany('App\Price');
}
}
User model relationship //a user can claim 1 or more prices
class User extends Model
{
public function prices ()
{
return $this->hasMany('App\Price');
}
}
=============== MY Product Controller ===============
This is the tricky part here on how to get the price of all customers except retailer:
class ProductController extends Controller
{
public function show($id)
{
$product = Product::findOrFail($id);
// This query should return all price claimed by customers except retailer. But the problem is, it only return 1 row, the first row which the output is 10.00.
$query_customer =$product->prices()->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
});
$latest_price_by_customer= $query_customer->value('price');
dd($latest_price_by_customer);
//it just return 1 row: price 10.00
/* It should return the collection that I can do foreach statement. The output should be like this:
10.00
6.00
5.00
7.00
8.00
*/
}
}
The query in the controller above return all prices claimed by customers except retailer. But the problem is, it only return 1 row, the first row which the output is 10.00.
It should output all prices claimed by customers from the prices table like below:
10.00
6.00
5.00
7.00
8.00
Any idea?
Update:
So far I changed my controller codes from this:
$product = Product::findOrFail($id);
$query_customer =$product->prices()->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
});
$latest_price_by_customer= $query_customer->value('price');
dd($latest_price_by_customer);
to this:
$product = Product::with('prices')->findOrFail($id);
$product_query= $product->prices()->where('product_id', $id) ->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
})->select('price')->get();
dd($product_query); //display collection and return the correct values
}
I have one small problem here: When loop through the collection
foreach($product_query->prices as $pr)
{
// dd($pr);
// echo $pr->price . ' ___ ' ;
}
I got an error of ErrorException in ProductController.php line 72:
Undefined property: Illuminate\Database\Eloquent\Collection::$prices
but the relationship is exist as shown.
If anyone looking for the answer this is the correct query that returns collection instead of 1 row:
$product = Product::with('prices')->findOrFail($id);
$product_query= $product->prices()->where('product_id', $id) ->whereHas('user', function ($q) {
$q->whereHas('roles', function ($q) {
$q->where('slug', 'customer');
});
})->select('price')->get();
foreach($product_query as $price)
{
echo $price->price;
}