Joining nested tables with conditions in MySQL and Laravel - php

I'm building an application on Laravel 7 where I'm having following models:
Company (table name companies)
id name created_at
1 Sample company 1 2018-09-17 17:47:03
Contracts (table name contract_awards)
id name company_id project_id created_at
1 Sample Project involved 1 1 2018-09-17 17:47:03
Project (table name projects)
id name state region
1 Sample Project 1 XYZ State ABC Region
Categories
id name
1 Residential
2 Commercial
categories_projects_table
id categories_id project_id
1 2 1
Currently I'm fetching the companies and project details, where in companies are being fetched with its own filters/parameters and projects are being fetched with its own filters/parameters, I'm able to join projects table and fetch the result as per condition but while applying categories filter I'm unable to fetch the data. I'm not sure if I'm doing it correct or not, my code is following:
Company::leftjoin('contract_awards', function ($join) {
$join->on('companies.id', '=', 'contract_awards.awarded_by');
})
->leftjoin('projects', function ($q) {
$q->on('contract_awards.project_id', '=', 'projects.id')
->when(request('state'), function ($q) {
$q->whereIn('state', collect(request('state')->pluck('id')));
})
->when(request('region'), function ($q) {
$q->whereIn('region', collect(request('region'))->pluck('id'));
})
->when(request('categories'), function ($q) {
$q->leftjoin('categories_projects_table', function($q) {
$q->on('projects.id', '=', 'categories_projects_table.project_id');
})
// currently checking with static IDs later will be changed to collect(request('categories'))->pluck('id')
->select('categories_projects_table.categories_id as project_categories_id')
->whereIn('project_categories_id', [1]);
});
})
->select('companies.*', 'projects.name as project_name', 'projects.area as project_area')
->paginate(15);
I mean to say that I want to filter projects with its category relation, Above code gives me error:
column not found: 1054 Unknown column 'project_categories_id' in 'on clause' (SQL: select count(*) as aggregate from companies left join contract_awards on companies.`id .........
Any better approach in executing this is most welcomed, thanks in advance.

Related

Laravel wherenotexists returning null

I have the following piece of code
$not_paid = Tenant::where('property_id', $property_id)
->whereNotExists(function ($query) use ($property_id) {
$query->select('user_id')
->from('rent_paids');
})
->get();
which is supposed to get all the tenants in a certain property, look them up in the rent_paids table and return the users who are not in the rent_paids table, as follows:
tenants table
Id
user_id
property_id
1
1
1
2
2
1
3
3
1
rent_paids
Id
user_id
property_id
amount_paid
1
1
1
3000
I want to be able to return the users in the tenants table and not in the rent_paids table. In this case, users 2 and 3. But the above code returns an empty array.
You're missing the where clause to tie it back to the original table.
$not_paid = Tenant::where('property_id', $property_id)
->whereNotExists(function ($query) use ($property_id) {
$query->select('user_id')
->from('rent_paids')
->whereColumn('tenants.user_id', '=', 'rent_paids.user_id');
})
->get();

How to get ID from table only if it contains multiple values needed, from different rows

I have a channel_members table containing channel_id, user_id. I need to get the channel_id if there are multiple rows using that same channel_id which contains multiple user_id that I will provide.
Example:
If there are 5 rows in the table
CHANNEL_ID | USER_ID
2 | 2
2 | 3
2 | 4
3 | 2
3 | 4
I need to get the channel_id which are being used by user_id 2, 3, and 4. So based in the table above that I provided. I should get channel_id 2.
I assume you have already defined your relations uisng models, As per your provided description, channel has many to many relation with user
class Channel extends Model
{
public function members()
{
return $this->belongsToMany('App\User', 'channel_members', 'channel_id', 'user_id');
}
}
Using eloquent realtions you can check existance of related models as
$channels = App\Channel::whereHas('members', function ($query) {
$query->where('id', '=', 2);
})->whereHas('members', function ($query) {
$query->where('id', '=', 3);
})->whereHas('members', function ($query) {
$query->where('id', '=', 4);
})->get();
Above will return you only channels who have associations with all 3 users based on supplied id
Querying Relationship Existence
SELECT CHANNEL_ID
FROM channel_members
WHERE USER_ID in (2,3,4)
GROUP BY CHANNEL_ID
HAVING COUNT(CHANNEL_ID) > 0

How to grab only latest update record from data table in Laravel 5.6?

I have following table name as projects like this structure,
id name adtype created_at updated_at
1 gobba 1 2018-02-25 2018-02-25
2 manna 0 2018-04-25 2018-04-25
3 alaya 1 2017-12-28 2017-12-28
I need grab only one result witch related to latest updated record and adtype == 1, I code following controller, for this,
public function showad()
{
$projects = Vehicle::with('uploads')
->where('adtype','=',1)
->latest('updated_at');
return view('vehicles.slider')->withProjects($projects);
but this working but not filtering latest updated records. how can correct this?
Try using ORDER BY and LIMIT:
$projects = Vehicle::with('uploads')
->where('adtype', '=', 1)
->orderBy('updated_at', 'desc')
->take(1)
->get();
This should correspond to the following raw MySQL query:
SELECT *
FROM uploads
WHERE adtype = 1
ORDER BY updated_at DESC
LIMIT 1;

How to get data from another table using ID from another table

I would like to get a data from a table to another table using it's primary key.
products_table:
id name type_id date_added
1 item1 2 1234
2 item2 2 5678
3 item3 1 0000
product_type_table:
id type_name
1 type1
2 type2
3 type3
I am querying the first table using this code:
Products::select('name','type_id')->where('id',$id)->get()
Now, how do I automatically get the type_name from the product_type_table using the type_id from the products_table?
As Jack Skeletron pointed out, the Laravel documentation has examples for joining 2 or multiple tables.
In your case
$products = DB::table('products_table')
->join('product_type_table', 'products_table.type_id', '=', 'product_type_table.type_id')
->select('products_table.name, products_table.type_id')
->where('id', $id)
->get();
you can use left join.
DB::table('product_type_table')
->leftJoin('products_table', 'product_type_table.id', '=', 'products_table.type_id ')->where('product_type_table.id',$id)
->get();
In Product Model add Below code for joining 2 tables:
use App\Models\ProductType;
public function type()
{
return $this->belongsTo(ProductType::class);
}
and change the line:
Products::select('name','type_id')->where('id',$id)->get()
to
Products::select('name','type_id')->with(['type' => function($q){
return $q->select('type_name');
}])->where('id',$id)->get()
Hope this works for you.

Laravel leftJoin only last record of right table

I am new to laravel.
I have two tables.
1) products
2) prices
-----------------------------
- products -
-----------------------------
- id_product | int (p_key) -
- name | varchar -
-----------------------------
-------------------------
- prices -
-----------------------------
- id_price | int (p_key) -
- id_product | int -
- price | int -
-----------------------------
the products table holds data about products like id, name,...
the price changes are stored in prices table where the last record is the newest price that should be displayed to users.
now I want to search through products and get the last price of each product from prices table. this is my query:
$result = DB::table('products')->leftJoin('prices', function($join) {
$join->on('products.id_product', '=', 'prices.id_product');
})->whereRaw(MY_SEARCH_FILTERS);
the above code is wrong because if a product has 4 records in prices table, then it will be repeated 4 times in $result, but only 1 record with the last price should be displayed.
Here we have 2 tables users and answers where users is left table and answers is right table which has user answers.
We wanted to left join users with answers but the join should be with the latest record or answers table.
$query = Users::select('users.id', 'users.user_name','answers.created_at as last_activity_date')
->leftJoin('answers', function($query)
{
$query->on('users.id','=','answers.user_id')
->whereRaw('answers.id IN (select MAX(a2.id) from answers as a2 join users as u2 on u2.id = a2.user_id group by u2.id)');
})
->where('users.role_type_id', Users::STUDENT_ROLE_TYPE)->get();
you can make make it easy by using Laravel Elquent:
class Product extends Model
{
public function lastPrice()
{
// optional: change id_price to created_at by add created_at to prices table
return $this->hasOne(Price::class)->orderBy('id_price', 'DESC');
}
}
now in
public function getProducts(){
$MY_SEARCH_FILTERS=....;
// get all products with last price
$products=Product::with('lastPrice')->whereRaw(MY_SEARCH_FILTERS)->get()
return $products
}
Here we have 2 tables 'articles' and 'comments' where articles is left table and comments is right table which has article's comments.
We wanted to left join articles with comments but the join should be with the latest record from comments table.
$query = Article::select('articles.*', 'comments.comment as article_comment')
->leftJoin('comments', function($query) {
$query->on('comments.article_id','=','articles.id')
->whereRaw('comments.id IN (select MAX(a2.id) from comments as a2 join articles as u2 on u2.id = a2.article_id group by u2.id)');
})
->get();
i found this solution from here https://laravelcode.com/post/how-to-get-last-record-from-leftjoin-table-in-laravel
You need to add two things in here,
1) orderBy descending on prices table.
2) first clause in the DB::table function (It will fetch only 1
record, that will be the latest price).
The solution :
$result = DB::table('products')
->leftJoin('prices',function($join)
{
$join->on('products.id_product', '=', 'prices.id_product')
})->whereRaw(MY_SEARCH_FILTERS)
->orderBy('prices.id_price','desc')
->first();
You can also use (Laravel 5.1) :
$result = DB::table('products')
->leftJoin('products.id','=','prices.id_product')
->whereRaw(MY_SEARCH_FILTERS)
->orderBy('prices.id_price','desc')
->first();

Categories