Laravel 4 select column from another table in subquery - php

I am attempting to do the equivalent of this:
select p.id, p.title, b.brand,
(select big from images where images.product_id = p.id order by id asc limit 1) as image
from products p
inner join brands b on b.id = p.brand_id
Here is where I am at now, but it of course doesn't work:
public function getProducts($brand)
{
// the fields we want back
$fields = array('p.id', 'p.title', 'p.msrp', 'b.brand', 'p.image');
// if logged in add more fields
if(Auth::check())
{
array_push($fields, 'p.price_dealer');
}
$products = DB::table('products as p')
->join('brands as b', 'b.id', '=', 'p.brand_id')
->select(DB::raw('(select big from images i order by id asc limit 1) AS image'), 'i.id', '=', 'p.id')
->where('b.active', '=', 1)
->where('p.display', '=', 1)
->where('b.brand', '=', $brand)
->select($fields)
->get();
return Response::json(array('products' => $products));
}
I don't really see anything in the docs on how to do this, and I can't seem to piece it together from other posts.
In "regular" SQL, the subquery is treated AS a column, but I am not sure how to string that together here. Thanks for any help on this.

I strongly recommend you to use Eloquent, instead of pure SQL. It's one of the most beautful things in Laravel. Two models and relations and it's done! If you need to use pure SQL like that, put it all in DB::raw. It's easier, simpler and (ironically) less messy!
With the models, you could use relations between the two tables (represented by the models itself) and say (so far I understood) that Brands belongs to Products, and Images belongs to Product. Take a look at Eloquent's documentation on Laravel. Probably will be more clearly.
Once the relations are done, you can only say that you wanna get
$product = Product::where(function ($query) use ($brand){
$brand_id = Brand::where('brand', '=', $brand)->first()->id;
$query->where('brand_id', '=', $brand_id);
})
->image()
->get();
That and a better look at Eloquent's documentation should help you to do the job.
P.S.: I didn't test the code before send it and wrote it by head, but i think it works.

Related

Laravel OrderBy by related table column

I have a table (A) that has a One to Many relation with another table (B).
I want to query Table A and eager load Table B with the Table A results - but I also want to sort Table A by a value in Table B.
I have tried using OrderBy in the query and also trying SortBy on the resultant collection but cannot get the Table A data to be sorted by the value found in Table B.
Example of what I have tried:
$query = ModelA::with("ModelB"])->get()->sortByDesc('ModelB.sortValue');
Keep in mind, I am only interested in the LATEST record from Table B. So I need to query Table A and sort by a value in the LATEST records of Table B.
How can I achieve this?
EDIT:
The below (as suggested by #ljubadr) works pretty close, but the issue is that there are many record in Table B which means that it doesn't reliably sort as it doesn't seem to sortby the latest records in Table B. Can I have the join return ONLY the latest record for each ID?
$query = ModelA::select('TableA.*')
->join('TableB', 'TableA.id', '=', 'TableB.col_id')
->groupBy('TableA.id')->orderBy('TableB.sortCol', 'desc')
->with(['x'])
->get();
EDIT 2:
#Neku80 answer has gotten me closest but it seems to not sort the column with the greatest accuracy.. I'm sorting a Decimal column and for the most part it is in order but in some places the items are out of order..
$latestTableB = ModelB::select(['TableA_id', 'sortByColumnName'], DB::raw('MAX(created_at) as created_at'))
->groupBy('TableA_id');
$query = ModelA::select('TableA.*')
->joinSub($latestTableB, 'latest_TableB', function ($join) {
$join->on('TableA.id', '=', 'latest_TableB.TableA_id');
})
->orderBy('latest_TableB.sortByColumnName')
->get();
For example, the ordering is like:
0.0437
0.0389
0.0247 <-- -1
0.025 <-- +1
0.0127
When I delete all rows except for the 'latest' rows, then it orders correctly, so it still must be ordering with old data...
I have found a solution:
ModelA::select('TableA.*', 'TableB.sortByCol as sortByCol')
->leftJoin('TableB', function ($query) {
$query->on('TableB.TableA_id', '=', 'TableA.id')
->whereRaw('TableB.id IN (select MAX(a2.id) from TableB as a2 join TableA as u2 on u2.id = a2.TableA_id group by u2.id)');
})
->orderBy('TableB.sortByCol')
->get();
Another alternative to order is like this:
$users = User::orderBy(
Company::select('name')
->whereColumn('companies.user_id', 'users.id'),
'asc'
)->get();
Here we are ordering in asc order by company name field.
In this article it is explained in detail.
You can simply execute a left join query:
ModelA::query()->leftJoin('model_b_table', 'model_a_table.primary_key', '=', 'model_b_table.foreign_key')->orderBy('model_a_table.target_column')->get();
This should work if you only need TableB's ID and created_at columns:
$latestTableB = ModelB::select('TableA_id', DB::raw('MAX(created_at) as created_at'))
->groupBy('TableA_id');
$query = ModelA::select('TableA.*')
->joinSub($latestTableB, 'latest_TableB', function ($join) {
$join->on('TableA.id', '=', 'latest_TableB.TableA_id');
})
->orderBy('latest_TableB.created_at')
->get();

Using multi where queries Laravel relationships

I have two tables (Table1, Table2).
I want to print the sum of the records whose properties match Table1 in Table2 while listing the Table1 table.
My two tables contain very large records, performance is important to me.
// Model -> relationships
public function cars()
{
return $this->hasMany('App\Models\Table2', 'list_id', 'list_id');
}
// Controller
$table1 = Table1::with('cars' => function($query){
$query->where('table2.color','=', 'table1.color')
$query->where('table2.year','=', 'table1.year')
}])
->get();
I'm adding the sample database pictures:
Thank you.
First, add below use statement to the top of your controller:
use DB;
Now, If you only want to get the records amount, you can do this:
$amount = DB::table('table1')
->join('table2', function($join){
$join->on('table1.color', '=', 'table2.color');
$join->on('table1.year', '=', 'table2.year');
})->count();
But if you want to get the list of the table1 records, you can change the query a bit like below:
$records = DB::table('table1')
->select('table1.*')
->join('table2', function($join){
$join->on('table1.color', '=', 'table2.color');
$join->on('table1.year', '=', 'table2.year');
})->count();
Please follow Laravel's official guide on this topic:
https://laravel.com/docs/8.x/queries#advanced-join-clauses
Use join to merge the two tables read more about join here https://www.w3schools.com/sql/sql_join.asp

Laravel Eloquent join with IN clause

I'm currently trying to use the Eloquent query builder to create a join with multiple clauses, one of which being an IN clause.
The type of query I would like to create would be
SELECT * FROM trusts t
LEFT JOIN trust_group tg ON tg.trust_id = t.id
AND tg.group_id IN (1,2,4)
I've tried
->leftJoin('trust_group', function($join) {
$join->on('trust_group.trust_id', '=', 'trusts.id');
$join->on('trust_group.group_id', 'IN', [1,2,4]);
})
which results in
and `trust_group`.`group_id` = `IN`
and I've also tried
->leftJoin('trust_group', function($join) {
$join->on('trust_group.trust_id', '=', 'trusts.id');
$join->on(DB::raw('trust_group.group_id IN (1,2,4)'));
})
but this results in a query containing something along the lines of
and trust_group.group_id IN (1,2,4) = ``
(Obviously those group IDs are for example purposes, and would by dynamic)
Can Eloquent support IN clauses on joins?
This is only part of a pretty large query, so would prefer to use the join rather than use a whereIn
As this is kinda deadlock at the moment, I am posting this as an answer until this is officially PRed. Unfortunately joining with an In clause is not yet supported officially. There are some discussions in this closed thread
You can use it as raw query :
<?php
$results = DB::select("
SELECT * FROM trusts t
LEFT JOIN trust_group tg ON tg.trust_id = t.id
AND tg.group_id IN (?)", $groupIds);
Also there is Model::hydrate($array) method if you want to have eloquent collection back from result array.
This is a pretty old post, but for anyone searching, you can now simply use where functions to build more complex joins (tested in Laravel 7) :
->leftJoin('trust_group', function($join) {
$join
->on('trust_group.trust_id', '=', 'trusts.id')
->whereIn('trust_group.group_id', [1, 2, 4])
;
})

How to create SQL Join Statement in Laravel Controller

I have two table customer_id namely tbl_customer and tbl_stocks connected on the same database. My logic about this problem is JOIN sql statement.
This is for Laravel and MySQL, so far i've tried this on PHP and is working fine but when I implement it on laravel it is not working i wonder why?
here is my code in PHP and want to convert it to laravel but I dont know where to put? will i put it in the View or in the Controller
$query = "SELECT c.*, s.* FROM tbl_customer c JOIN tbl_stock s ON s.customer_id = c.customer_id AND c.customer_id = 1";
Controller
$data = DB::table('tbl_customer')
->join ...... //Im not sure about this
->select .... // neither this
->get();
print_r($data)
Model
I have no codes on my model
Routes
Route::get('/admin/shopcontrol', 'Admin\ShopsController#testquery');
I expect a result of fetching or getting the query or result of the values in just a simple echo and the fetch join is connected
Have you checked the Laravel site?
https://laravel.com/docs/5.7/queries#joins
It has a demonstration you could use to reorganize your code.
As it follows below from the site.
Joins
Inner Join Clause
The query builder may also be used to write join statements. To perform a basic "inner join", you may use the join method on a query builder instance. The first argument passed to the join method is the name of the table you need to join to, while the remaining arguments specify the column constraints for the join. Of course, as you can see, you can join to multiple tables in a single query:
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();
You may find more information there if it suits you.
Try this:
$data = DB::table('tbl_customer')
->join('tbl_stock', 'customer_id', '=', 'tbl_customer.customer_id')
->select('tbl_customer.*', 'tbl_stock.*')
->where('customer_id', '=', 1)
->get();

Find auctions for a user in eloquent

I'm working with L5 and elequent
My table structure is..
users
id
other field
auctions
id
other field
lots
id
auction_id
other field
lot_user
lot_id
user_id
I want to find auctions for a user.
How can i do this?
$user = User::find($id);
$auctions = $user->auctions();
I have got an idea to do this with eloquent..
$auctions = $user->lots()
->join('auctions','auctions.id','=','lots.id')
->select(['auctions.*'])
->get();
I'm not sure Eloquent is going to be very efficient here, but you could do something like :
In your User(s) class, you need to define a many-many relationship like :
public function lots()
{
return $this->belongsToMany('App\Lot');
}
In your Lot(s) class, you need to define the inverse of a one-to-many relationship like:
public function auctions()
{
return $this->belongsTo('App\Auction')
}
Then, to get Lots for a user, you'd do something like :
$user->lots();
To get auctions, you'd need to loop over lots and call $lot->auctions() for each one, and then filter by id to get the unique auctions.
This is a case where it would probably be easier to use the DB facade to built a query instead of just trying to use Eloquent.
About DB facade.
Raw query will looks like this:
SELECT * FROM auctions AS a
INNER JOIN lots AS l ON (l.auction_id = a.id)
INNER JOIN lot_user AS lu ON (lu.lot_id = l.id AND lu.user_id = $findUserId)
GROUP BY a.id
And using query-builder you can do it like this:
DB::table('auctions')
->join('lots', 'lots.auction_id', '=', 'auctions.id')
->join('lot_user', function ($join) {
$join->on('lot_user.lot_id', '=', 'lots.id')
->where('lot_user.user_id', '=', $findUserId);
})
->groupBy('auctions.id')
->get();

Categories