Laravel where in query [duplicate] - laravel

This question already has answers here:
How to do this in Laravel, subquery where in
(12 answers)
Closed 7 years ago.
How would I do this with Laravel?
SELECT movie.title
FROM movie
WHERE movie.id IN
(SELECT session.movie_id FROM session WHERE session.id = :id and date = :date)

Use DB::raw to run raw queries
$query = DB::select(DB::raw("select movie.title
FROM movie
where movie.id in
(select session.movie_id from session where session.id = $id and date = $date);"));
return $query;

You can make use of laravel's advanced-wheres:
$movie = Movie::whereIn('id', function($query) use ($id, $date) {
$query->select(DB::raw('session.movie_id'))
->from('session')
->whereRaw('session.id = ? and session.date = ? array($id, $date));
})
->get();

First off you will need a database with movies and sessions tables and two models in Laravel.
Movie Model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Movie extends Model {
protected $fillable = ['title'];
public function sessions()
{
return $this->hasMany('App\Session');
}
}
?>
Session Model
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Session extends Model {
public function movies()
{
return $this->belongsTo('App\Movie','movie_id');
}
?>
The query in your Controller would have a method like.
public function show($id)
{
try {
$movie = Movie::with('sessions')->where('id',$id)->firstOrFail();
}
catch(ModelNotFoundException $exception)
{
abort(404);
}
return view('movies.show')->withMovie($movie);
}

However you use laravel ORM, it will generate more than one query, i would recommend you to just query in session table first and get the list, then use that result in your wherein query in movie model.

$query = "select movie.title from movie where movie.id IN ( SELECT session.movie_id FROM session WHERE session.id ='".$id."' and date = '".$date."' );
$resultSet = DB::select($query);
Hope this helps.

Use Left Join.
For example,
$first = DB::session('movie.title')->leftjoin('session','session.movie_id','=','movie.id')->where('session.id', '=', $id)->where('session.date','=','$date')->get();
To check results,
dd(first);
Hope this helps.

$query = "SELECT movie.title
FROM movie
WHERE movie.id IN
(SELECT session.movie_id FROM session WHERE session.id = ? and date = ?)";
$movie = \DB::select($query, [$id, $date]);

Using LEFT JOIN is a good option for optimized code. Otherwise Check the below explanation.
The following line of code will generate the query to fetch the movie id's. Using "toSql()" method will return the query instead of result.
$movie_id_qry = DB::table('session')->select('session.movie_id')->whereRaw('session.id = '. $id .' && date = '. $date)->toSql();
This query can be included to fetch the movie title likewise:
$movie_title = DB::table('movies')->where('movie.id', '=', $movie_id_qry)->pluck('movie.title');
For result : echo $movie_title;
The "pluck()" method will return only the title column if match found.
To retrieve the entire row use the "get()" method instead of "pluck()".
As the "toSql()" method will only generate the query, the combined DB fetching only happens in the second line of code.
Hope this is helpful.

DB::table('movies')
->select(
movies.title,
DB::raw(
'(select session.movie_id from session where session.id = id AND date = date') as movie_id'
)
)->where('movies.id','movie_id')get();

Related

How can I convert native PHP7 into query eloquent Laravel?

I'm migrating from php 7 to laravel and am having trouble completing the query. how to solve data query like the example below
$year = date('Y');
$month = date('m');
select id, tglupload,
substring(CONVERT(varchar,tglupload,106),4,2) date,
COUNT(1) as Totalemployeall
from [MS_SK]
where substring(CONVERT(varchar,tglupload,106),4,2) = $month
and substring(CONVERT(varchar,tglupload,106),7,4) = $year
AND (status_allow <> 'NOTALLOW' OR status_allow is null)
GROUP BY rollup(id, tglupload)
order by id ASC
Unfortunately you have to use a raw query for that. But you can make your query nicer using the Laravel's scope function.
For example in your model (the model related with the table [MS_SK]) you can add the following 2 scope functions:
class YourModel extends Model {
public function scopeFiltrateTglUpload($query, int $month=null, int $year=null)
{
$year = $year ?? date('Y');
$month = $month ?? date('m');
return $query->where(\DB::raw("substring(CONVERT(varchar,tglupload,106),4,2)", "=", $month))
->where(\DB::raw("substring(CONVERT(varchar,tglupload,106),7,4)", "=", $year));
}
public function scopeTheStatusIsNullOrNotAllowed($query)
{
return $query->where(function($subQuery) {
$subQuery->where('status_allow', '<>', 'NOTALLOW')
->orWhereNull('status_allow');
});
}
}
Then you can use them as per below:
$result = YourModel::selectRaw('
`id`, `tglupload`,
substring(CONVERT(varchar,tglupload,106),4,2) `date`,
COUNT(1) as `Totalemployeall`
')
->filtrateTglUpload()
->theStatusIsNullOrNotAllowed()
->groupBy(\Db::raw('rollup(id, tglupload)'))
->orderBy('id')
->get();
Please note that this is just an example to give you an idea. Then you should make it work :) Please tell me in the comment if you need any help.

Laravel Pivot Table, Get Room belonging to users

The structure of my pivot table is
room_id - user_id
I have 2 users that exist in the same room.
How can I get the rooms they both have in common?
It would be nice to create a static class to have something like this.
Room::commonToUsers([1, 5]);
Potentially I could check more users so the logic must not restrict to a certain number of users.
Room::commonToUsers([1, 5, 6, 33, ...]);
I created a Laravel project and make users, 'rooms', 'room_users' tables and their models
and defined a static function in RoomUser Model as below :
public static function commonToUsers($ids)
{
$sql = 'SELECT room_id FROM room_users WHERE user_id IN (' . implode(',', $ids) . ') GROUP BY room_id HAVING COUNT(*) = ' . count($ids);
$roomsIds = DB::select($sql);
$roomsIds = array_map(function ($item){
return $item->room_id;
}, $roomsIds);
return Room::whereIn('id', $roomsIds)->get();
}
in this method, I use self join that the table is joined with itself, A and B are different table aliases for the same table, then I applied the where condition between these two tables (A and B) and work for me.
I hope be useful.
I don't know the names of your relations, but I guess you can do like this :
$usersIds = [1, 5];
$rooms = Room::whereHas('users', function($query) use ($usersIds) {
foreach ($usersIds as $userId) {
$query->where('users.id', $userId);
}
})->get();
It should work. whereHas allows you to query your relation. If you need to have a static method, you can add a method in your model.
There might be a more efficient way but laravel collection does have an intersect method. You could create a static function that retrieves and loop through each object and only retain all intersecting rooms. something like this
public static function commonToUsers($userArr){
$users = User::whereIn('id',$userArr)->get();
$rooms = null;
foreach($users as $user){
if($rooms === null){
$rooms = $user->rooms;
}else{
$rooms = $rooms->intersect($user->rooms);
}
}
return $rooms;
}
This code is untested but it should work.
Room has many users, user has many rooms, so you can find the room which have those two users.
If your pivot table's name is room_users, then you can easily get the common room like this:
public static function commonToUsers($user_ids) {
$room = new Room();
foreach($user_ids as $user_id) {
$room->whereHas('users', function($query) use ($user_id) {
$query->where('room_users.user_id', $user_id);
});
}
return $room->get();
}
This code will convert to raw sql:
select *
from `rooms`
where exists (
select * from `rooms` inner join `room_users` on `rooms`.`id` = `room_users`.`room_id` where `rooms`.`id` = `room_users`.`room_id` and `room_users`.`user_id` = 1
)
and exists
(
select * from `rooms` inner join `room_users` on `rooms`.`id` = `room_users`.`room_id` where `rooms`.`id` = `room_users`.`room_id` and `room_users`.`user_id` = 5
)

The equivalence of the AND statement in a ON statement (JOIN) in EloquentORM

Take a look at the query below:
SELECT v*, s.*
FROM videos v
INNER JOIN subtitles s ON (s.subtitle_id = v.video_id AND s.language = 'en')
WHERE v.video_id = 1000
I want to find the equivalent data retrieval action for a Laravel / Eloquent ORM environment.
So, my options are:
using the DB facade
using the query builder
defining the relationship in the Video model
Let's say I wish to use the latter (if possible).
namespace App\Models\v1;
use App\Models\v1\Subtitles;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
protected $table = 'videos';
public function subtitle()
{
return $this->hasOne(Subtitles::class, 'subtitle_id', 'video_id'); // How can I define the AND s.language = 'en' ?
}
}
The problem here is that I don't know how to define the AND s.language = 'en' in EloquentORM.
Any help is appreciated.
You can add a where clause to the relationship:
public function subtitle()
{
return $this->hasOne(Subtitles::class, 'subtitle_id', 'video_id')->whereLanguage('en');
}
Retrieving the model:
Provided you changed your primaryKey property on the video model:
protected $primaryKey = 'video_id';
Docs
You can do the following:
$video = Video::findOrFail(1000);
$subtitle = $video->subtitle;
You can define the relationship and then use whereHas
public function subtitle()
{
return $this->hasOne(Subtitles::class, 'subtitle_id', 'video_id');
}
And then filter it like this
$video = Video::where('video_id', 1000)->whereHas('subtitle', function($query){
$query->where('language', 'en');
})->first();
For details check the doc
If you just want to use join then you can use it like this
$lang = 'en';
$video = Video::where('video_id', 1000)
->join('subtitles', function ($join) use ($lang){
$join->on(function ($query) use ($lang) {
$query->on('subtitles.subtitle_id', '=', 'videos.video_id');
$query->on('subtitles.language', '=', DB::raw($lang));
});
})->first();
Check laravel join

Error Number: 1066 Not unique table/alias: 'core_user'

I have 3 tables in a database.
core_user
core_company
ct_company
i want to join 2 tables core_user and core_company where foriegn key is cmp_id column..
but it shows an error.
Error Number: 1066
Not unique table/alias: 'core_user'
SELECT * FROM (core_user, core_user) JOIN core_company ON core_company.cmp_id = core_user.cmp_id WHERE usr_email = 'fahad#gmail.com' AND usr_password = '123456' AND cmp_name = 'corpoleave'
Filename: F:/xampp/htdocs/corpoLeave/application/models/loginmodel.php
Line Number: 10
here is my model. please help. thanks
<?php class LoginModel extends CI_Model{
public function login_valid($email,$password,$cname){
$q= $this->db->where(['usr_email'=>$email,'usr_password'=>$password,'cmp_name'=>$cname])
->from('core_user');
$this->db->join('core_company', 'core_company.cmp_id = core_user.cmp_id');
$q = $this->db->get('core_user')->result();
if($q->result()==true)
{
return $q->row()->user_id;
}
else{
return false;
}
}}
?>
In the Codeigniter Query Builder, the get() and from() methods perform similarly.
As seen on the Codeigniter docs:
get()
$query = $this->db->get('mytable');
// Produces: SELECT * FROM mytable
from()
$this->db->select('title, content, date');
$this->db->from('mytable');
$query = $this->db->get();
// Produces: SELECT title, content, date FROM mytable
Both the get("tablename") and from("tablename") methods effectively append FROM tablename to the built statement, looking something like this:
$this->db->select('title, content, date');
$this->db->from('mytable');
$query = $this->db->get('mytable');
// Produces: SELECT title, content, date FROM mytable FROM mytable
(Notice the double "FROM" statement)
You are getting the error because you are using both from() and get() with tablenames. You can either remove the from() statement, or remove the tablename from the get() statement.
This would look like:
<?php
class LoginModel extends CI_Model {
public function login_valid($email, $password, $cname) {
$this->db->where(['usr_email' => $email, 'usr_password' => $password, 'cmp_name' => $cname]);
$this->db->from('core_user');
$this->db->join('core_company', 'core_company.cmp_id = core_user.cmp_id');
$q = $this->db->get();
if ($q->result()) {
return $q->row()->user_id;
} else {
return false;
}
}
}

Add custom column to identify table during query

How can I add a custom column in an Eloquent select query in order to identify the table?
For example, I have the current query:
$posts = Post::where('user_id', getUserID())
->get();
I'd like to add a column is_post with value 1 (for true) during the query.
The Post class:
<?php
class Post extends Eloquent {
protected $table = 'posts';
}
How can I do this?
You could do it for example this way:
$posts = Post::where('user_id', getUserID())->selectRaw('*, 1 AS `is_post`')->get();
but depending on your needs, you can also use the piece of code you showed:
$posts = Post::where('user_id', getUserID())->get();
and add accessor in Post model this way:
public function getIsPostAttribute($value) {
return 1;
}
In both cases you should be able to display is_post value for example this way:
foreach ($posts as $post) {
echo $post->is_post;
}

Resources