I'm trying to work with a semi-complex query (by my standards, anyway) but I can't think how to do it using the query builder or using eloquent relationships.
My relationships table is: user_id_1 | user_id_2 | status | action_user_id in the case of friends, action_user_id can be ignored and status = 1. There is only one row per relationship so if you want to select all relationships that belong to User 17 then you need to check both user_id_1 and user_id_2 because the id could be in either column. I followed the database structure from here: http://www.codedodle.com/2015/03/social-network-friends-relationship.html
The sort of query I'm trying to perform is:
SELECT users.*
FROM users
LEFT JOIN users_relationships AS r
ON (
users.id = r.user_id_1
AND r.user_id_1 != $user_id
) OR (
users.id = r.user_id_2
AND r.user_id_2 != $user_id
)
WHERE r.status = 1
AND (
r.user_id_1 = $user_id
OR r.user_id_2 = $user_id
)
Such a thing would be best in an eloquent relationship so it would be easy to perform: $user->friends and it would return the results of the above but I'm stuck in all directions.
My best attempt unfortunately not using relationship is this:
User::with('profile')->join('user_relationships as r', function($join) use ($user_id) {
$join->on(DB::raw('( users.id = r.user_id_1 AND r.user_id_1 != ? )', [$user_id]), DB::raw(''), DB::raw(''));
$join->orOn(DB::raw('( users.id = r.user_id_2 AND r.user_id_2 != ? )', [$user_id]), DB::raw(''), DB::raw(''));
})
->where('r.status', 1)
->where(function($query) use ($user_id) {
$query->where('r.user_id_1', $user_id)
->orWhere('r.user_id_2', $user_id);
})
->get(['users.*']);
This however gives me errors relating to the parameters:
SQLSTATE[HY093]: Invalid parameter number (SQL: select `users`.* from `users` inner join `user_relationships` as `r` on ( users.id = r.user_id_1 AND r.user_id_1 != 1 ) or ( users.id = r.user_id_2 AND r.user_id_2 != 30 ) where `users`.`deleted_at` is null and `r`.`status` = 30 and (`r`.`user_id_1` = ? or `r`.`user_id_2` = ?))
I'm not sure how to do what I want to do.
The problem is here:
DB::raw('( users.id = r.user_id_1 AND r.user_id_1 != ? )', [$user_id])
DB::raw() doesn't take a second parameter for bindings. Use ->on()->where() instead (thanks to user4621032):
->leftJoin('users_relationships AS r', function($join) use($user_id) {
$join->on('users.id','=','r.users_id_1')->where('r.users_id_1','!=',$user_id)
->orOn('users_id','=','r.users_id_2')->where('r.users_id_2','!=',$user_id);
})
So to setup your ->friends() function as desired, you can use:
public function friends()
{
$user_id = $this->id;
return self::with('profile')
->leftJoin('users_relationships AS r', function($join) use($user_id) {
$join->on('users.id','=','r.users_id_1')->where('r.users_id_1','!=',$user_id)
->orOn('users_id','=','r.users_id_2')->where('r.users_id_2','!=',$user_id);
})
->where('r.status', 1)
->where(function($query) use ($user_id) {
$query->where('r.user_id_1', $user_id)
->orWhere('r.user_id_2', $user_id);
})
->get(['users.*']);
}
might be like this
DB::table('users')
->leftJoin('users_relationships AS r', function($join) use($user_id){
$join->on('users.id','=','r.users_id_1')->where('r.users_id_1','!=',$user_id)
->orOn('users_id','=','r.users_id_2')->where('r.users_id_2','!=',$user_id);
})
->where('r.status',1)
->where('r.user_id_1','=',$user_id)
->orWhere('r.user_id_2','=',$user_id)
->get();
Related
select * from `eplan_vacancy` where `reference_id` in
(select `eplan_ep_details`.`reference_id`
from `eplan_ep_details`
inner join `eplan_court_cases` on `eplan_ep_details`.`reference_id` = `eplan_court_cases`.`reference_id`
where `ep_cc_status` = 1
group by `eplan_court_cases`.`reference_id`)
and `is_form_submitted` = 1
and `st_code` in ('U05', 'S13', 'S01')
group by `reference_id`
order by `created_at` desc
You can use closure as the second parameter of the whereIn method.
whereIn($column, $values, $boolean = 'and', $not = false)
$return = DB::table('eplan_vacancy')
->whereIn('reference_id', function ($query) {
return $query->select('eplan_ep_details.reference_id')
->from('eplan_ep_details')
->join('eplan_court_cases', 'eplan_ep_details.reference_id', '=', 'eplan_court_cases.reference_id')
->where('ep_cc_status', 1)
->groupBy('eplan_court_cases.reference_id');
})
->where('is_form_submitted', 1)
->whereIn('st_code', ['U05', 'S13', 'S01'])
->groupBy('reference_id')
->orderBy('created_at', 'desc');
dd($return->toSql());
Result
select * from `eplan_vacancy` where `reference_id` in
(
select `eplan_ep_details`.`reference_id`
from `eplan_ep_details`
inner join `eplan_court_cases` on `eplan_ep_details`.`reference_id` = `eplan_court_cases`.`reference_id`
where `ep_cc_status` = ?
group by `eplan_court_cases`.`reference_id`
)
and `is_form_submitted` = ?
and `st_code` in (?, ?, ?)
group by `reference_id`
order by `created_at` desc
Here is a full eloqent query that you can use to generate above query, Here i used Models that you need to change according to your model name.
EplanVacnacy: Model for table "eplan_vacancy"
$result = EplanVacnacy::whereIN('reference_id',function($q){
$q->from('eplan_ep_details')
->select('eplan_ep_details.reference_id')
->innerJoin('eplan_court_cases','eplan_ep_details.reference_id','=','eplan_court_cases.reference_id')
->where('eplan_ep_details.ep_cc_status',1)
->groupBy('eplan_court_cases.reference_id')
->get();
return $q;
})
->where('is_form_submitted',1)
->whereIN('st_code',['U05', 'S13', 'S01'])
->groupBy('reference_id')
->orderBy('created_at','desc')
->get();
I have News table and the column in the blade table posted by is empty but in my news table the column users_id which is the posted by has a users_id value. I cant get the user who posted the specific news in specific school. I already have a working query for the news, but the problem is i cant join the users table where the name of the user who posted the news is in there. Can someone know what are the problem of my query? Help will be appreciated. Thanks
Index controller
public function index()
{
//testing query that returns an error
$userschool = Newsboard::select('users.name', 'news.school_id')
->join('users', 'users.id', '=', 'news.users_id')
->where('school_id', Auth::user()->school_id)->get();
//the query that i want still returns an error because of the auth
$postedby = DB::select(
"SELECT news.*, users.name as postedby from news
JOIN users on news.users_id = users.id
WHERE news.school_id AND news.active = 1 AND news.school_id = 'Auth::user()->school_id'");
//working queries and i dont know how to convert the $postedby query join to eloquent.
if (Auth::user()->role == 0) {
$news = Newsboard::where('active','=',1)->get();
} elseif (Auth::user()->role == 1 || Auth::user()->role == 5) {
$news = Newsboard::where('school_id', '=', Auth::user()->school_id )
->where('active','=',1)
->get();
} else {
$role = Auth::user()->role;
$news = Newsboard::where('school_id', '=', Auth::user()->school_id )
->where('status', '=', 1)
->where('active','=',1)
->whereRaw("group_id in('$role', '0')")
->get();
}
dd($userschool);
return view('admin.pages.news.index', [
'page_title' => $this->page_title,
'news' => $news,
'mnuname' => 'News',
]);
}
Set your Auth::user()->school_id as variable
$school_id = Auth::user()->school_id;
//the query that i want still returns an error because of the auth
$postedby = DB::select(
"SELECT news.*, users.name as postedby from news
JOIN users on news.users_id = users.id
WHERE news.school_id AND news.active = 1 AND news.school_id = '$school_id'");
Or this:
Newsboard::select('users.name', 'news.school_id')
->join('users', 'users.id', '=', 'news.users_id')
->where(['news.school_id' => $school_id])->get();
Because both users and news table contain school_id column, so in where condition must has table prefix.
Please try:
$userschool = Newsboard::select('users.name', 'news.school_id')
->join('users', 'users.id', '=', 'news.users_id')
->where('news.school_id', Auth::user()->school_id)->get();
//or
//the query that i want still returns an error because of the auth
$postedby = DB::select("SELECT news.*, users.name as postedby from news
JOIN users on news.users_id = users.id
WHERE news.school_id AND news.active = 1 AND news.school_id = '".Auth::user()->school_id."'");
$school_id = Auth::user()->school_id;
$userschool = Newsboard::select('users.name', 'news.school_id')
->join('users', 'users.id', '=', 'news.users_id')
->where('school_id', $school_id)->get();
I have the following MySQL query:
SELECT
*
FROM
news_posts
WHERE
user_id = ?
AND id NOT IN (SELECT
post_id
FROM
user_read
WHERE
user_id = ?)
I want to make it more "eloquent". I've tried the following, but its (obviously) not working:
NewsPost::where('user_id', Auth::id())
->whereNotIn(function ($query) {
$query->DB::table('user_read')
->select('post_id')
->where('user_id', Auth::id());
})->get();
I'm assuming the 'where' method is executing a simple SQL query on 'new_posts' table. Can you try to rewrite this query and let mysql do the filtering for new posts? (search for LEFT OUTER JOIN on mysql)
SELECT *
FROM news_posts a
JOIN user_read b
ON a.id = b.post_id
WHERE a.user_id = ?
AND b.post_id IS NULL;
Thanks for all the replies! Got it working with the following tweaks:
NewsPost::where('user_id', Auth::id())
->whereNotIn('id', function ($query) {
$query->select('post_id')
->from('user_read')
->where('user_id', Auth::id());
})
->get();
I am trying to make the following query in laravel:
SELECT a.name AS subname, a.area_id, b.name, u. id, u.lawyer_id,u.active_search,
FROM subarea a
LEFT JOIN user_subarea u ON u.subarea_id = a.id
AND u.user_id = ?
LEFT JOIN branch b ON a.area_id = b.id
The idea is to obtain the subareas and see if the search is activated by the user.
The user_subarea table might have a record that matches the id of the subarea table where the active_search is equal to 0 or 1. If it doesn't exist I would like the query to return null.
While I was able to achieve this in raw SQL when I try the same with eloquent in Laravel I am not returning any value. I have done the following:
$query = DB::table('subarea')
->join('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Any help will be much appreciated.
I found by myself the answer it was just to add a lefjoin in the first join. It is not in the laravel docs but works too.
$query = DB::table('subarea')
->lefjoin('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Try this one, If you get a problem, please comment.
$value = \Auth::user()->id;
$query = DB::table('subarea')
->where('user_subarea.user_id', '=',$value)
->leftJoin('user_subarea', 'subarea.id', '=', 'user_subarea.subarea_id')
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('subarea.name AS subname','subarea.area_id', 'branch.name', 'user_subarea.id','user_subarea.lawyer_id','user_subarea.active_search')
->get();
I do currently have this code:
return Datatable::query($query = DB::table('acquisitions')
->where('acquisitions.deleted_at', '=', null)
->where('acquisitions.status', '!=', 2)
->join('contacts', 'acquisitions.contact_id', '=', 'contacts.id')
->join('user', 'acquisitions.user_id', '=', 'user.id')
->select('contacts.*', 'acquisitions.*', 'acquisitions.id as acquisitions_id', 'user.first_name as supervisor_first_name', 'user.last_name as supervisor_last_name', 'user.id as user_id'))
The data from the user table is used for 2 columns: acquisitions.supervisor_id and acquisitions.user_id. I need the first_name and the last_name for both of this tables, the above query does however currently only use the id from the acquisitions.user_id field. I also tried to use a table alias, that does also not work, I assume that I'm doing something wrong here.
So in short: I also need that the query selects the data for the user, based on the id from the acquisitions.supervisor_id and makes it available as supervisor_first_name and supervisor_last_name.
According to your next to last comment on the other answer, you need a self join per reference table. Try this:
$result = DB::select('SELECT
u.name user_first_name,
u.last_name user_last_name,
u.email user_email,
s.name supervisor_name,
s.last_name supervisor_last_name,
s.email supervisor_email
FROM acquisitions a
JOIN users u ON a.user_id = u.id
JOIN users s ON a.supervisor_id = s.id');
return $result;
Note that $result is an array of StdClass objects, not a Collection, but you can still iterate it and call the current item's values:
foreach ($result as $item) {
print($item->supervisor_first_name);
}
If you need a WHERE clause, e.g. to get a specific user's row from acquisitions, you would do that by adding a parameter to the query like so:
$result = DB::select('SELECT
u.name user_first_name,
u.last_name user_last_name,
u.email user_email,
s.name supervisor_name,
s.last_name supervisor_last_name,
s.email supervisor_email
FROM acquisitions a
JOIN users u ON a.user_id = u.id
JOIN users s ON a.supervisor_id = s.id
WHERE a.user_id = ?
', [3]);
EDIT
If you need the resultset to be a Collection, you can easily convert the array to one, using the hydrate method:
$userdata = \App\User::hydrate($result); // $userdata is now a collection of models
It should be something like;
return Datatable::query($query = DB::table('acquisitions')
->where('acquisitions.deleted_at', '=', null)
->where('acquisitions.status', '!=', 2)
->join('contacts', 'acquisitions.contact_id', '=', 'contacts.id')
->join('user', 'acquisitions.user_id', '=', 'user.id')
->select( \DB::raw(" contacts.*, acquisitions.*, acquisitions.id as acquisitions_id, user.first_name as supervisor_first_name, user.last_name as supervisor_last_name, user.id as user_id ") )
);
$devices = DB::table('devices as d')
->leftJoin('users as au', 'd.assigned_user_id', '=', 'au.id')
->leftJoin('users as cu', 'd.completed_by_user_id', '=', 'cu.id')
->select('d.id','au.name as assigned_user_name','cu.name as completed_by_user_name');
Also follow this link
https://github.com/yajra/laravel-datatables/issues/161