mysql join ON and AND to laravel eloquent - mysql

I've been able to get the query result I need using the following raw sql:
select `person`.`id`, `full_name`, count(actions.user_id) as total
from `persons`
left join `actions`
on `actions`.`person_id` = `persons`.`id`
and `actions`.`user_id` = $user
where `type` = 'mp'
group by `persons`.`id`
But I haven't been able to get it working in eloquent yet.
Based on some similar answers, I'd tried functions within ->where() or leftJoin(), but the count of each person's actions isn't yet being filtered by $user. As it stands:
$query = Person::leftJoin('actions', function($q) use ($user)
{
$q->on('actions.person_id', 'persons.id')
->where('actions.user_id', $user);
})
->groupBy('persons.id')
->where('type', 'foo')
//->where('actions.user_id', '=', $user)
->get(['persons.id', 'full_name', DB::raw('count(actions.id) as total')]);
I'm at least heading in roughly the right direction, right...?
If it's relevant, the Persons.php model has two actions relationships:
public function actions()
{
return $this->hasMany('Action');
}
public function actionsUser($id)
{
return $this->hasMany('Action')->where('user_id', $id);
}

So, for reference, I solved it like so:
$query = Person::leftJoin('actions', function($q) use ($user)
{
$q->on('actions.person_id', '=', 'persons.id')
->where('actions.user_id', '=', "$user");
})
->groupBy('persons.id')
->where('type', 'foo')
->get(['persons.id', 'full_name', DB::raw('count(actions.id) as total')]);
The ->where() clause within leftJoin, oddly, needs the speech marks for the variable to be passed through the sql query correctly (likewise, '2' doesn't seem to work while "2" does).

I found that the where doesn't always work on the leftJoin clause
If in the future you get any trouble with it, I'd suggest you using this:
$query = Person::leftJoin('actions', function($q) use ($user)
{
$q->on('actions.person_id', '=', 'persons.id')
->on('actions.user_id', '=', "$user");
})
->groupBy('persons.id')
->where('type', 'foo')
->get(['persons.id', 'full_name', DB::raw('count(actions.id) as total')]);
Hope it helps someone.

When laravel eloquent just start getting complex like this
For more flexibility and readability I'll just use plain sql statement then hydrate the results.
$sql = "
SELECT `person`.`id`,
`full_name`,
count(actions.user_id) AS total
FROM `persons`
LEFT JOIN `actions`
ON `actions`.`person_id` = `persons`.`id`
AND `actions`.`user_id` = $user
WHERE `type` = 'mp'
GROUP by `persons`.`id`
";
$query = Person::hydrate(
DB::select( $sql )
);

Related

how to run mysql query in Laravel

I want to transform my MySql query into a Query in Laravel but I really don't know how to do this. I don't know how to rename in FROM like in SQL
My query is the following one :
SELECT f2.* FROM formation f2 WHERE f2.theme_id IN
(SELECT f.theme_id FROM user_formation uf JOIN formation f ON uf.formation_id = f.id WHERE uf.user_id = 2)
AND f2.id NOT IN
(SELECT formation_id FROM user_formation WHERE user_id = 2);
I tried something like this but ...
$q = Formation::query()
->from('formation AS f2')
->whereIn('f2.theme_id', function($r)
{
$r->select('f.theme_id')->from('user_formation AS uf')
->join('formation', function($join)
{
$join->on('uf.formation_id', '=', 'f.id')
->where ('uf.user_id', '=', $id)
});
});
->whereNotIn('f2.id', function($s){
$s->select('formation.id')
->from('user_formation')
->where('user_id', '=', $id)
})->get();
thanks for help.
If you want to run this raw query you can run:
$res = DB::select('
SELECT f2.*
FROM formation f2
WHERE f2.theme_id IN
(SELECT f.theme_id FROM user_formation uf JOIN formation f ON uf.formation_id = f.id WHERE uf.user_id = 2)
AND f2.id NOT IN
(SELECT formation_id FROM user_formation WHERE user_id = 2)');
Or you can rewrite this query in laravel query builder Eloquent ORM:
Formations::query()
->whereIn('formations.theme_id', function($q){
$user_formations_table = (new UserFormation)->getTable();
$formation_table = (new Formation)->getTable();
$q->select('paper_type_id')
->from($user_formations_table)
->join($formation_table, "$user_formations_table.formation_id", '=', "$formation_table.id")
->where("$user_formations_table.user_id", 2);
})->whereNotIn('formations.id', function($q){
$user_formations_table = (new UserFormation)->getTable();
$q->select('formation_id')
->where("$user_formations_table.user_id", 2);
})
->get();
Note that I have used models Formations, UserFormation, Formation Because you have used 3 different tables, you should add this models and specify tables to run ORM query
I advice to run first RAW query if there is no another need to run it with Eloquent
Hope this helps you
First of all, you need to fix your code indentations so you don't confuse yourself. Second, you placed semicolon in the wrong places. Third, you need to pass $id inside function because of the variable scope.
$q = Formation::query()
->whereIn('f2.theme_id', function($r) use ($id) {
$r->select('f.theme_id')->from('user_formation AS uf')
->join('formation', function($join) use ($id) {
$join->on('uf.formation_id', '=', 'f.id')
->where('uf.user_id', '=', $id);
}
);
})
->whereNotIn('f2.id', function($s) use ($id) {
$s->select('formation.id')
->from('user_formation')
->where('user_id', '=', $id);
})->get();
Note : If you are using VSCode, I suggest to use PHP Intelephense as it will help with autocomplete, syntax check, etc.

checking for multiple values in a single column in laravel 5

So I'm not sure whether I asked the question well. I'm new to laravel and right now I'm building an application where I need to fetch data for a user if certain conditions are met. This is what I'm trying to achieve:
Select from database where userid = $user and userstatus = active or inactive. or pending.
So all rows with the user id($user) and status(active, inactive and pending) will be returned.
I tried doing:
$users = DB::table('users')
->where('status', '=', 'active')
->orwhere('status', '=', 'inactive')
->orwhere('status', '=', 'pending')
->get();
This returned all the data in that particular table. What is the best way to go about this.
You have at least two options for how to do this you can use, including both so you have one for use in this case and one for general usage. Using a function in where creates a new block, so works like adding parentheses to your query
$users = DB::table('users')
->where('id', $user)
->where(function($query) {
$query->where('status', 'active')
->orWhere('status', 'inactive')
->orWhere('status', 'pending');
})->get();
or
$users = DB::table('users')->where('id', $user)->whereIn('status', ['active', 'inactive', 'pending'])->get();
You can do it as:
$users = DB::table('users')
->where('userid', $userid)
->whereIn('status',['active', 'inactive','pending'])
->get();

Sql leftJoin query using laravel syntax showing error

This is my query that i used for left join, it is working fine but something is missing when I convert it to laravel syntax.
Query to convert is
$result = DB::select("select amenities.name as
name,amenities.type_id,amenities.id as id, amenities.icon, rooms.id as status
from amenities left join rooms on find_in_set(amenities.id, rooms.amenities)
and rooms.id = $room_id and type_id !=4");
and the I am doing this
$result = DB::table('amenities')
->select('amenities.name as name', 'amenities.type_id' , 'amenities.id as id'
, 'amenities.icon', 'rooms.id as status' )
->leftJoin('rooms', function ($join) {
$join->on('FIND_IN_SET(amenities.id, rooms.amenities)')
->where('rooms.id' , '=', '$room_id')
->where('type_id','!=', 4);
})->get();
The error is
InvalidArgumentException in
F:\xampp\htdocs\arheb\Arheb\vendor\laravel\framework\src\Illuminate\Database\Query\JoinClause.php
line 79: Not enough arguments for the on clause.
Your query is wrong. I assume that amenities.id and rooms.amenities are attributes of amenities and rooms table respectively.
MySQL FIND_IN_SET() returns the position of a string if it is present (as a substring) within a list of strings.
You need to pass column names in first and second parameter of on() function.
$result = DB::table('amenities')
->select('amenities.name as name', 'amenities.type_id' , 'amenities.id as id'
, 'amenities.icon', 'rooms.id as status' )
->leftJoin('rooms', function ($join) {
$join->on('amenities.id', '=', 'rooms.amenities')
->where('rooms.id' , '=', '$room_id')
->where('type_id','!=', 4);
})->get();
I think you can try this:
$result = DB::table('amenities')
->select('amenities.name as name', 'amenities.type_id' , 'amenities.id as id'
, 'amenities.icon', 'rooms.id as status' )
->leftJoin('rooms', function ($join) {
$join->on(DB::raw("find_in_set(amenities.id, rooms.amenities)"))
->where('rooms.id' , '=', '$room_id')
->where('type_id','!=', 4);
})->get();
Hope this work for you!

PDO wrong bindings with Laravel

I have a search query that works perfect (I stripped some unimportant code):
$posts = new Post;
if(Input::has('query')) {
// Search for posts with title or tags matching the given criteria
$posts = $posts
->addSelect(DB::raw("MATCH(posts.title) AGAINST (?) as post_score"))
->addSelect(DB::raw("MATCH(tags.title) AGAINST (?) as tag_score"))
->where(function($query) {
return $query
->whereRaw('MATCH(posts.title) AGAINST (?)')
->orWhereRaw('MATCH(tags.title) AGAINST (?)');
})
->orderBy(DB::raw('post_score+tag_score'), 'desc')
->setBindings([ $input['query'], $input['query'], $input['query'], $input['query'] ]);
}
But as soon as I add this piece of code before the above if() statement:
if(Input::has('filter')) {
$posts = $posts->whereType($input['filter']); //Filter type by either 'article' or 'question'
}
... I get this error:
[2014-11-04 19:28:18] production.ERROR: PDO error: SQLSTATE[HY093]: Invalid parameter number (SQL: select `posts`.*, COALESCE(SUM(post_votes.rating), 0) as rating, MATCH(posts.title) AGAINST (css) as post_score, MATCH(tags.title) AGAINST (css) as tag_score from `posts` left join `post_tags` on `post_tags`.`post_id` = `posts`.`id` left join `tags` on `tags`.`id` = `post_tags`.`tag_id` left join `post_votes` on `post_votes`.`post_id` = `posts`.`id` where `type` = css and (MATCH(posts.title) AGAINST (css) or MATCH(tags.title) AGAINST (?)) group by `posts`.`id` order by post_score+tag_score desc, `views` desc) [] []
I entered css as search query, the type should be filtered on question. As you can see the variables aren't binded right (don't know the right word for this). How could this be? I also tried this which doesn't work:
->where(function($query) use ($input) {
return $query
->whereRaw('MATCH(posts.title) AGAINST (?)', [$input['query']])
->orWhereRaw('MATCH(tags.title) AGAINST (?)', [$input['query']]);
})
Thanks in advance.
This is what you need:
if(Input::has('filter')) {
$posts->whereType($input['filter']); //Filter type by either 'article' or 'question'
}
if(Input::has('query')) {
// no need for this:
// $posts = $posts
// just:
$posts
->addSelect(DB::raw("MATCH(posts.title) AGAINST (?) as post_score"))
->addBinding($input['query'], 'select')
->addSelect(DB::raw("MATCH(tags.title) AGAINST (?) as tag_score"))
->addBinding($input['query'], 'select')
->where(function($query) use ($input) {
$query
->whereRaw('MATCH(posts.title) AGAINST (?)', [$input['query']])
->orWhereRaw('MATCH(tags.title) AGAINST (?)', [$input['query']]);
})
->orderBy(DB::raw('post_score+tag_score'), 'desc')
}

How to add brackets around WHERE conditions with Laravel query builder

I'm using the Laravel query builder to dynamically filter data based on a user's filter selections:
$query = DB::table('readings');
foreach ($selections as $selection) {
$query->orWhere('id', $selection);
}
$query->whereBetween('date', array($from, $to));
$query->groupBy('id');
When I examine the SQL, I get something like this:
select count(*) as `count` from `readings` where `id` = 1 or id` = 2 and `date` between "2013-09-01" and "2013-09-31" group by `id`;
But what I need is something like this (with brackets around the or statements):
select count(*) as `count` from `readings` where (`id` = 1 or id` = 2) and `date` between "2013-09-01" and "2013-09-31" group by `id`;
How do I add brackets around WHERE conditions with Laravel query builder?
Very useful, I use this:
->where(function ($query) use ($texto){
$query->where('UPPER(V_CODIGO)', 'LIKE', '%'.Str::upper($texto).'%')
->orWhere('UPPER(V_NOMBRE)', 'LIKE', '%'.Str::upper($texto).'%');
});
I couldn't find this in documentation, whereNested was what I was looking for. Hope it helps anybody.
$q->whereNested(function($q) use ($nameSearch) {
$q->where('name', 'LIKE', "%{$nameSearch}%");
$q->orWhere('surname', 'LIKE', "%{$nameSearch}%");
});
Note: This is on Laravel 4.2
Solved this myself by using a closure, as described in Parameter Grouping in the query builder documentation.
$query = DB::table('readings');
$this->builder->orWhere(function($query) use ($selections)
{
foreach ($selections as $selection) {
$query->orWhere('id', $selection);
}
});
$query->whereBetween('date', array($from, $to));
$query->groupBy('id');
Sometimes you may need to group several "where" clauses within parentheses in order to achieve your query's desired logical grouping. In fact, you should generally always group calls to the orWhere method in parentheses in order to avoid unexpected query behavior. To accomplish this, you may pass a closure to the where method:
$users = DB::table('users')
->where('name', '=', 'John')
->where(function ($query) {
$query->where('votes', '>', 100)
->orWhere('title', '=', 'Admin');
})
->get();
As you can see, passing a closure into the where method instructs the query builder to begin a constraint group. The closure will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group. The example above will produce the following SQL:
select * from users where name = 'John' and (votes > 100 or title = 'Admin')
You can use WHERE IN here for the same effect:
$query = DB::table('readings');
$query->whereIn('id', $selection)
$query->whereBetween('date', array($from, $to));
$query->groupBy('id');