Laravel Eloquent - Select MAX with other columns - php

I'm trying to select a number of columns along with MAX. The raw query would be something like: SELECT users.id, ..., MAX(ur.rank) AS rank but I cannot figure out how to do it using the query builder supplied by Laravel in Eloquent.
This is my attempt:
$user = User::join('users_ranks AS ur', function($join) {
$join ->on('ur.uid', '=', 'users.id');
})
->where('users.id', '=', 7)
->groupBy('users.id')
->first(['users.id', 'users.username', 'MAX(ur.rank) AS rank']);
I simply cannot figure it out. What I want to achieve is I'm selecting a user where users.id = 7, and I'm wanting to select the MAX rank that's in users_ranks where their users_ranks.uid = users.id.
I was told to avoid sub-queries as when working with large result sets, it can slow things down dramatically.
Can anyone point me in the right direction? Thanks.

I think you should rewrite it like this:
DB::table('users')
->select(['users.id', 'users.username', DB::raw('MAX(ur.rank) AS rank')])
->leftJoin('users_ranks AS ur', 'ur.uid', '=', 'users.id')
->where('users.id', '=', 7)
->groupBy('users.id')
->first();
No sense to use User:: if you use table names later and want to fetch not all of the fields ( 'users.id', 'users.username' ).

Related

How can I select data rows by id in a database query?

I have a database query that needs filtering further. The id needs to match a number in an array I have. For some reason, I can select where using every column except id. Even something as simple as $query->where('users.id', 1); doesn't work. How can I perform a database query by id?
$portfolio_query_array = UserPortfolio::all()->pluck('user_id')
$query = DB::table('users');
$query->select('users.id as user_id','users.user_slug', 'users.social_id', 'users.social_img_update_status', 'users.avatar', 'users.first_name', 'users.last_name', 'users.bio', 'comments.rating', 'user_portfolios.title', 'user_portfolios.description', 'user_portfolios.filepath');
$query->leftjoin('comments', 'comments.comment_to', '=', 'users.id');
$query->leftjoin('user_portfolios', 'user_portfolios.user_id', '=', 'users.id');
$query->leftjoin('user_profile_category_selects', 'user_profile_category_selects.user_id', '=', 'users.id');
$query->where('users.status', 1);
$query->where('users.user_type', 3);
// The below simple query line doesn't work
$query->where('users.id', 1);
// The lines I do want to work also fail.
foreach ($portfolio_query_array as $user_id){
$query = $query + $query->where('users.id', $user_id);
}
Thank you for your help!
First of all, you should take advantage of Eloquent ORM, there is no need to use raw queries unless you have some performance issues or really complex queries.
Assuming you have 3 models User, UserPortfolio, Comment, and all relationships defined, you could do something as simple as this:
$users = User::with('comments', 'portfolio')
->where('status', 1)
->where('user_type', 3)
->whereHas('portfolio')
->get();
In this way, you are getting all users with portfolios which is what I assume you want.
Anyway, if you insist to use a raw query, there whereIn() method is what you need
$portfolio_query_array = UserPortfolio::pluck('user_id')->toArray();
$query = DB::table('users')
->select(
'users.id as user_id',
'users.user_slug',
'users.social_id',
'users.social_img_update_status',
'users.avatar',
'users.first_name',
'users.last_name',
'users.bio',
'comments.rating',
'user_portfolios.title',
'user_portfolios.description',
'user_portfolios.filepath'
)
->leftjoin('comments', 'comments.comment_to', 'users.id')
->leftjoin('user_portfolios', 'user_portfolios.user_id', 'users.id')
->leftjoin('user_profile_category_selects', 'user_profile_category_selects.user_id', 'users.id')
->where('users.status', 1)
->where('users.user_type', 3)
->whereIn('users.id', $portfolio_query_array)
->get();
BTW, why are you doing a leftJoin to user_profile_category_selects if no fields are selected from that table?
In addition, if you are looking for all users that have a portfolio, starting from the whole list of portfolios, wouldn't be better to do a join to portfolios and get only those users having portfolios?
$query = DB::table('users')
->select(
'users.id as user_id',
'users.user_slug',
'users.social_id',
'users.social_img_update_status',
'users.avatar',
'users.first_name',
'users.last_name',
'users.bio',
'comments.rating',
'user_portfolios.title',
'user_portfolios.description',
'user_portfolios.filepath'
)
->leftjoin('comments', 'comments.comment_to', 'users.id')
->join('user_portfolios', 'user_portfolios.user_id', 'users.id')
->leftjoin('user_profile_category_selects', 'user_profile_category_selects.user_id', 'users.id')
->where('users.status', 1)
->where('users.user_type', 3)
->get();

How to join tables with more than one attribute match?

I am trying to turn my raw sql into laravel query builder and I encounter difficulty on how to join multiple tables using with many attributes match.
In this case, I want to join the table jr_h and jr_d with three attributes match (book,p_seq and staff_code) rather than one (book).
Raw sql:
$sql = "select from_time,to_time,t.staff_code,s.name_t as staff_name,t.book,t.p_code,t.p_seq,p.hrs1,s.img_file,
t.hrs_work,p.sharing_cnt as hrs_work, t.hrs_ot as hrs_ot from jr_d as t
inner join jr_h as p on(t.book=p.book and t.p_seq=p.p_seq and t.staff_code=p.staff_code)
inner join astaff as s on(t.staff_code=s.staff_code) ";
Laravel query builder:
$jr_d = DB::table('jr_d')
->join('jr_h', 'jr_d.book', '=', 'jr_h.book')
->join('astaff', 'jr_d.staff_code', '=', 'astaff.staff_code')
->select('jr_h.*','jr_d.*','astaff.*','astaff.name_t as staff_name')
->where('jr_d.ref_group','=','E')
->get();
and also want to know if there is a way to make the query faster since it has a lot of data in the tables.
Laravel joins with multiple conditions:
$results = DB::table('jr_d')
->select('jr_h.*','jr_d.*','astaff.*','astaff.name_t as staff_name')
->join('jr_h', 'jr_d.book', '=', 'jr_h.book')
->join('jr_h as p', function($query){
$query->on('t.book','=', p.book');
$query->on('t.p_seq','=', 'p.p_seq');
$query->on('t.staff_code', '=', 'p.staff_code');
})
->where('jr_d.ref_group','=','E')
->get();
`
Try this:
// ...
->join('jr_h p', function($join) {
$join->on('t.book', '=', 'p.book');
$join->on('t.p_seq', '=', 'p.p_seq');
// ... more conditions
});
Try this.
$jr_d = DB::table('jr_d')
->join('jr_h', 'jr_d.book', '=', 'jr_h.book')
->join('astaff', 'jr_d.staff_code', '=', 'astaff.staff_code')
->select('*','astaff.name_t as staff_name')
->where('jr_d.ref_group','=','E')
->get();

Laravel - Select only specified columns in joined tables

Here's my situation I have joined tables but the problem is some of those columns have the same name from other tables. What I want to know is how I can prevent this from happening. The columns that have the same name are created_at but I only want to use methods' table created_at (methods.created_at). Here is my code to explain my situation better
$filtered_table = Method::leftJoin('users', 'users.id', '=', 'methods.created_by')
->leftJoin('roles', 'roles.id', '=', 'users.role_id')
->leftJoin('types', 'types.id', '=', 'methods.type_id')
->where($request->filters)//will act as a searchmap
->get([ 'users.username', 'users.id AS users_id', 'methods.*', 'methods.id AS method_id', 'methods.name AS method_name', 'roles.id AS role_id', 'roles.name AS role_name',
'types.id AS type_id_typetable', 'types.name AS type_name']);
notice how ->where is an array of objects, I am using it as a searchmap for the clause. But my problem is like what I said above that the tables has the same name on some columns like for example created_at, the other columns doesn't matter since I am not using it.
The question is how do I explicitly tell the query that I am using the methods.created_at when I am searching it through the searchmap (In this case, $request->filters['created_at']. Please, let me know if you need any more details.
EDIT
if($("#date_select_off").val() == "daily") {
let day = $("#day_date").val();
filter_list.created_at = day;
}
in this code in jquery I am naming the key the same as the column so that I can use it as parameter in the php query. But my like my initial problem I simply can't name it filter_list.methods.created_at any help with this is greatly appreciated.
EDIT 2
How would I use a 'LIKE' query to that particular key value pair?
->where($request->filters)//will act as a searchmap
->orWhere('methods.created_at', 'LIKE', $request->filters['methods.created_at'])
I tried doing this but it is just wrong since the key value pair is already hitting on the first where clause.
EDIT 3
It could use some improvements but yeah
$filtered_table = Method::leftJoin('users', 'users.id', '=', 'methods.created_by')
->leftJoin('roles', 'roles.id', '=', 'users.role_id')
->leftJoin('types', 'types.id', '=', 'methods.type_id')
->where($request->filters)//will act as a searchmap
->orWhere('methods.created_at', 'LIKE', '%' . $request->filters['methods.created_at'] . '%')
->get([ 'users.username', 'users.id AS users_id', 'methods.id AS method_id', 'methods.name AS method_name', 'methods.created_at AS method_created_at', 'roles.id AS role_id', 'roles.name AS role_name',
'types.id AS type_id_typetable', 'types.name AS type_name']);
Change your model class as per your requirements to specify what columns you want selected:
public function someModel() {
return $this->belongs_to('otherModel')->select(array('id', 'name'));
}
In this case pass the fully qualified column name in where clause like:
->where('methods.created_at', '=', $request->filters)
or create a table alias and use the alias like:
SELECT col from methods as t1,
...
WHERE t1.col = 'some value';

Eloquent - join clause with string value rather than column heading

I have a question regarding join clauses in Eloquent, and whether you can join on a string value rather than a table column.
I have the code below querying a nested set joining parent/child records in a table 'destinations' via a table 'taxonomy'.
The second $join statement in the closure is the one causing an issue; Eloquent assumes this is a column, when I would actually just like to join on t1.parent_type = 'Destination' - ie, t1.parent_type should = a string value, Destination.
$result = DB::connection()
->table('destinations AS d1')
->select(array('d1.title AS level1', 'd2.title AS level2'))
->leftJoin('taxonomy AS t1', function($join) {
$join->on('t1.parent_id', '=', 'd1.id');
$join->on('t1.parent_type', '=', 'Destination');
})
->leftJoin('destinations AS d2', 'd2.id', '=', 't1.child_id')
->where('d1.slug', '=', $slug)
->get();
Is it possible to force Eloquent to do this? I've tried replacing 'Destination' with DB::raw('Destination') but this does not work either.
Thanking you kindly.
Another best way to achieve same is :
$result = DB::connection()
->table('destinations AS d1')
->select(array('d1.title AS level1', 'd2.title AS level2'))
->leftJoin('taxonomy AS t1', function($join) {
$join->on('t1.parent_id', '=', 'd1.id');
$join->where('t1.parent_type', '=', 'Destination');
})
->leftJoin('destinations AS d2', 'd2.id', '=', 't1.child_id')
->where('d1.slug', '=', $slug)
->get();
Replace your on with where
try using DB::raw("'Destination'")

Count rows in Laravel 4 database

Hi I am trying to get the current count of my statement below , but I am getting only the count not the whole result:
$admins = DB::table('users')
->select(DB::raw('count(users.id) as admin_count'))
->where('users_roles.role_id', '=' ,0)
->join('users_roles', 'users.id', '=', 'users_roles.user_id')
->orderBy('first_name', 'asc')
->get();
Could you tell me what I am doing wrong?
Thanks
Just use * in your SELECT clause, and you get entire resultset. Then, $admins is an array, and you can get its count using count method.
$admins = DB::table('users')
->select('users.*')
->join('users_roles', 'users.id', '=', 'users_roles.user_id')
->where('users_roles.role_id', '=' ,0)
->get();
I assume you have users_roles.role_id = 0 for exactly once for a user. There are no multiple entries for role_id = 0 for one user right?
I hope this helps.
Or you can use...
$admins = User::roles()->where('role_id', '=', 0)->count();
If the relations are setup correctly that should work.
Resource: http://laravel.com/docs/eloquent#many-to-many
I am not sure how laravel handles nested selects with the query builder, in plain sql, it would look like this
SELECT users.id, (SELECT COUNT(users.id) FROM users) AS admin_count
FROM users
JOIN users_roles
ON user_roles.id = users.id
WHERE users_roles.role_id = 0
ORDER BY first_name
which I am pretty sure you can just assign to a variable and run it like $admins = DB::query($sql)

Categories