Laravel Eloquent Select CASE? - sql

Is there anyone with experience in PHP & Laravel Eloquent who can help me resolve this statement? I'm trying to inject a CASE... WHEN.. END... inside a raw() method. It seemed like it was completely ignored. The existing documentation hasn't been . I've tried several different things to no prevail. I'm trying to pull this off:
SELECT shares.id, ...,
CASE WHEN users.id = <CurrentUser> THEN 1 ELSE 0 END AS is_user,
...
FROM <table>
...
The source code is below:
$shares = Share::where('shares.status', '=', SHARE_STATUS_APPROVED)
->where('shares.deleted', '=', '0')
->where('locations.lat', '<=', $nelat)
->where('locations.lat', '>=', $swlat)
->where('locations.lng', '>=', $nelng)
->where('locations.lng', '<=', $swlng)
->where('users.id', '=', $user)
->orWhere('shares.connected_user_id', '=', $user)
->join('users', 'shares.user_id', '=', 'users.id')
->join('locations', 'locations.id', '=', 'users.location_id')
->join('provinces', 'provinces.id', '=', 'locations.province_id')
->join('countries', 'countries.id', '=', 'locations.country_id')
->select('shares.id AS share_id', 'users.id AS user_id', 'shares.connected_user_id', 'shares.original_language_id', 'shares.image',
'users.first_name', 'users.last_name', 'users.email',
'locations.city', 'provinces.name', 'countries.code',
'locations.lat', 'locations.lng',
'shares.created_at')
->raw('(CASE WHEN users.id = ' . $user . ' THEN 1 ELSE 0 END) AS is_user')
->orderBy('shares.created_at', 'desc')
->orderBy('users.id', 'asc')
->orderBy('shares.connected_user_id', 'asc')
->get();

Move your raw() call inside the SELECT statement:
->select('shares.id AS share_id', 'users.id AS user_id', 'shares.connected_user_id',
'shares.original_language_id', 'shares.image',
'users.first_name', 'users.last_name', 'users.email',
'locations.city', 'provinces.name', 'countries.code',
'locations.lat', 'locations.lng',
'shares.created_at',
DB::raw('(CASE WHEN users.id = ' . $user . ' THEN 1 ELSE 0 END) AS is_user')
)
->orderBy('shares.created_at', 'desc')
From: https://laravel.com/docs/5.4/queries#raw-expressions

Alternatively you can use selectRaw instead.
->selectRaw("shares.id AS share_id, users.id AS user_id ,
shares.connected_user_id ,
shares.original_language_id, shares.image,
users.first_name, users.last_name, users.email,
locations.city, provinces.name, countries.code,
locations.lat, locations.lng,
shares.created_at,
(CASE WHEN users.id = {$user} THEN 1 ELSE 0 END) AS is_user)")
->orderBy('shares.created_at', 'desc')

Just recently I have created a package that adds CASE support for Eloquent Query Builder. You can check it out here: https://github.com/aglipanci/laravel-eloquent-case
Using the package you can do this:
use App\Models\Invoice;
use AgliPanci\LaravelCase\Query\CaseBuilder;
$invoices = Invoice::query()
->case(function (CaseBuilder $case) {
$case->when('balance', '<', 0)->then('Overpaid')
->when('balance', 0)->then('Paid')
->else('Balance Due');
}, 'payment_status')
->get();

Related

Convert SQL with nested queries to Laravel Eloquent

I need to convert this query that I got from Access to an Laravel eloquent for my remake database project, and this is what i did but i haven't the same result with the origin sql thanks.
SELECT T_Sites.Code_Region, T_Sites.Nom_Site, T_CLM.N_CLM, T_Port.N_Port,
T_Vlan.IP_Vlan, T_Ref_Vlan.Id_Referentiel, T_Ref_Vlan.Nom_Vlan,
T_Vlan.Dt_Creat, T_Vlan.Id_Vlan, T_Vlan.IP_HSRP, T_Vlan.IP_SousReseaux,
T_CLM.Id_CLM, T_Vlan.Masque
FROM (T_CLM
INNER JOIN (
(T_Port INNER JOIN T_Vlan ON T_Port.Id_Port = T_Vlan.Id_Port)
LEFT JOIN T_Ref_Vlan ON T_Vlan.Id_Referentiel = T_Ref_Vlan.Id_Referentiel
)
ON T_CLM.Id_CLM = T_Port.Id_CLM)
INNER JOIN T_Sites ON T_CLM.Id_Site = T_Sites.Id_Site
ORDER BY T_CLM.Id_CLM DESC
WITH OWNERACCESS OPTION;
// what i did
$SuiviVlan = DB::table('T_CLM')
->join('T_Sites', 'T_CLM.Id_Site', '=', 'T_Sites.Id_Site')
->join('T_Port', 'T_CLM.Id_CLM' , '=', 'T_Port.Id_CLM')
->join('T_Vlan', 'T_Vlan.Id_Port', '=', 'T_Port.Id_Port')
->leftjoin('T_Ref_Vlan', 'T_Ref_Vlan.Id_Referentiel', '=', 'T_Vlan.Id_Referentiel')
->select('T_Sites.Code_Region','T_Sites.Nom_Site','T_CLM.N_CLM','T_Port.N_Port','T_Vlan.IP_Vlan',
'T_Ref_Vlan.Id_Referentiel', 'T_Ref_Vlan.Nom_Vlan', 'T_Vlan.Dt_Creat', 'T_Vlan.Id_Vlan', 'T_Vlan.IP_HSRP',
'T_Vlan.IP_SousReseaux', 'T_CLM.Id_CLM', 'T_Vlan.Masque')
->orderBy('T_CLM.Id_CLM', 'desc')
->get();
// It was the correct laravel eloquent , thanks btw for help.
$SuiviVlan = DB::table('T_CLM')
->join('T_Sites', 'T_CLM.Id_Site', '=', 'T_Sites.Id_Site')
->join('T_Port', 'T_CLM.Id_CLM' , '=', 'T_Port.Id_CLM')
->join('T_Vlan', 'T_Vlan.Id_Port', '=', 'T_Port.Id_Port')
->leftjoin('T_Ref_Vlan', 'T_Ref_Vlan.Id_Referentiel', '=', 'T_Vlan.Id_Referentiel')
->select('T_Sites.Code_Region','T_Sites.Nom_Site','T_CLM.N_CLM','T_Port.N_Port','T_Vlan.IP_Vlan',
'T_Ref_Vlan.Id_Referentiel', 'T_Ref_Vlan.Nom_Vlan', 'T_Vlan.Dt_Creat', 'T_Vlan.Id_Vlan', 'T_Vlan.IP_HSRP',
'T_Vlan.IP_SousReseaux', 'T_CLM.Id_CLM', 'T_Vlan.Masque')
->orderBy('T_CLM.Id_CLM', 'desc')
->get();

Laravel using a case statement

I'm trying to retrieve all messages of a conversation and display it's status (read or unread). With a CASE I try to read the message.read property (boolean) and process it to a string.
$messages = DB::table('conversation_message')
->select(
'messages.id as message_id',
'messages.created_at as send_at',
'messages.user_id as from_id',
'messages.body as body',
'conversations.id as conversation',
DB::raw('(CASE WHEN messages.read = 1 THEN read ELSE unread END) AS status')
)
->leftjoin('messages', 'messages.id', '=', 'conversation_message.message_id')
->leftjoin('conversations', 'conversations.id', '=', 'conversation_message.conversation_id')
->orderBy('send_at', 'asc')
->get();
Without the CASE, the query works fine but with the case I recieve a Syntax error or access violation: 1064 near 'read.
Solved it by placing both the outcomes read and unread in double quotes.
$messages = DB::table('conversation_message')
->select(
'messages.id as message_id',
'messages.created_at as send_at',
'messages.user_id as from_id',
'messages.body as body',
'conversations.id as conversation',
DB::raw('(CASE WHEN messages.read = 1 THEN "read" ELSE "unread" END) AS status')
)
->leftjoin('messages', 'messages.id', '=', 'conversation_message.message_id')
->leftjoin('conversations', 'conversations.id', '=', 'conversation_message.conversation_id')
->orderBy('send_at', 'asc')
->get();
Now I can use the status directly as a css class!

Laravel 5: Join On with IN query

I'm trying to do something like:
$results = $query->leftJoin('checklist_items', function($join) use ($days) {
$join->on('users.id', '=', 'checklist_items.user_id')
->on('checklist_items.due_date', 'IN', $days);
})
->where('checklist_items.user_id', null)
->limit(10)
->get();
This is an example of the query I'm attempting to execute:
SELECT *
FROM users
LEFT JOIN checklist_items
ON users.id = checklist_items.user_id
AND checklist_items.due_date IN ('2015-07-09', '2015-07-10')
WHERE checklist_items.user_id IS NULL
ORDER BY users.id
So this is a left outer join. In query builder, most of this is no problem. The problem is the fact that my AND line uses an IN query. If it were part of a WHERE clause I would use ->whereIn but since I need it in the Join clause, whereIn won't work and there is no orIn or some such.
Suggestions?
You can use ->whereIn() within the ->leftJoin() closure (Tested in Laravel 5.7.16):
$days = ['2015-07-09', '2015-07-10'];
$results = \DB::table('users')
->leftJoin('checklist_items', function($join) use ($days) {
$join->on('users.id', '=', 'checklist_items.user_id')
->whereIn('checklist_items.due_date', $days);
})
->where('checklist_items.user_id', null)
->orderby('users.id')
->get();
Output from dd(\DB::getQueryLog(); produces your example query:
array:1 [▼
0 => array:3 [▼
"query" => "select * from `users` left join `checklist_items` on `users`.`id` = `checklist_items`.`user_id` and `checklist_items`.`due_date` in (?, ?) where `checklist_items`.`user_id` is null order by `users`.`id` asc ◀"
"bindings" => array:2 [▼
0 => "2015-07-09"
1 => "2015-07-10"
]
"time" => 6.97
]
]
I think you would need to use DB::raw() so it doesn't try to quote your days and wrap your days in parenthesis as well. This should do the trick.
$days = '(\'2015-07-09\', \'2015-07-10\')';
$results = DB::table('users')->leftJoin('checklist_items', function($join) use ($days) {
$join->on('users.id', '=', 'checklist_items.user_id')
->on('checklist_items.due_date', 'IN', DB::raw($days));
})
->where('checklist_items.user_id', null)
->limit(10)
->toSql();
echo $results;
This Query will Work
$results = DB::table('users')
->join('checklist_items','checklist_items.user_id','=','users.id')
->whereIn('checklist_items.due_date',['2015-07-09', '2015-07-10'])
->whereNull('checklist_items.user_id')
->orderBy('users.id','asc')
For Laravel 7 and above use whereIn instead of on :
$join->on('users.id', '=', 'checklist_items.user_id')
->whereIn('checklist_items.due_date',$days);

Multi join select query on Laravel

How to write this query in Laravel. I am new in laravel.
Example:
SELECT * FROM ((respassanger join ((`reservation` join flightres
on flightres.res_id = reservation.id)) on respassanger.res_id = reservation.id)
join passanger on respassanger.pas_id = passanger.pas_id)
Have you read the documentation? Checkout Laravel's query builder. Using your table names as mentioned, work from the following example in the docs for your needs:
DB::table('users')
->join('contacts', function($join)
{
$join->on('users.id', '=', 'contacts.user_id')->orOn(...);
})
->get();
So something like:
DB::table('respassanger')
->join('reservation', function($join)
{
$join->on('flightres.res_id', '=', 'reservation.id')
})
->join('passanger', 'respassanger.pas_id', '=', 'passanger.pas_id')
->select( ... )
->get();
Not sure how correct the above is, but tweak it if it doesn't work.

Select sql code in Laravel

Following query returning six values
SELECT tbl_start FROM timetable inner join route ON tbl_rte_id = id WHERE rte_origin = "UL" and rte_destination = "HW" ORDER BY(tbl_start) DESC;
And my laravel code is returning only one value
$tables = Timetable::join('route', 'tbl_rte_id', '=', 'id')
->where('rte_origin', $origin, 'AND')
->where('rte_destination', $destination)
->orderBy('tbl_start', 'desc')
->get();
foreach ($tables as $table) {
$result[$table->id] = $table->tbl_start;
}
This laravel code is not similar or similar. Can anyone help me.
Change this part:
->where('rte_origin', $origin, 'AND')
// to:
->where('rte_origin', $origin)
It will know by default that it's AND operator
And if you want to provide this operator, then do this:
->where('rte_origin', '=', $origin, 'AND')
You may try something like this:
$tables = Timetable::join('route', 'tbl_rte_id', '=', 'timetable.id')
->where('rte_origin', $origin)
->where('rte_destination', $destination)
->orderBy('tbl_start', 'desc')
->get()->lists('tbl_start', 'id');
The $tables will contain an array of id => tbl_start pairs.
Add a listener in your routes.php
Event::listen('illuminate.query', function($sql){
var_dump($sql);
});
Then execute both queries and check if you have the same result