Laravel using a case statement - sql

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!

Related

sql query last_messages displays wrong message

i have query like this, but displays wrong last_message.
$users = Message::join('users', function ($join) {
$join->on('messages.from_id', '=', 'users.id')
->orOn('messages.to_id', '=', 'users.id');
})
->where(function ($q) {
$q->where('messages.from_id', auth()->user()->id)
->orWhere('messages.to_id', auth()->user()->id);
})
->where('users.id','!=',auth()->user()->id)
->select([
'users.id',
'users.name',
'users.avatar',
DB::raw('MAX(messages.created_at) max_created_at'),
DB::raw('MAX(messages.body) last_message'),
DB::raw('CASE WHEN(COUNT(messages.is_read) FILTER (WHERE is_read = false
AND messages.from_id != '.auth()->user()->id.') = 0) THEN true ELSE false END is_read'),
DB::raw('COUNT(messages.is_read) FILTER (WHERE is_read = false
AND messages.from_id != '.auth()->user()->id.') count_unread')
])
->orderBy('max_created_at', 'desc')
->groupBy('users.id')
->paginate($request->per_page ?? 20)
->withQueryString();
when i change
DB::raw('MAX(messages.body) last_message'),
to
DB::raw('messages.body ORDER BY messages.created_at DESC LIMIT 1 last_message'),
display error messages like this, syntax error at or near "last_message". How to fix this?
You want to alias the column, not the statement. Try to change it to:
messages.body last_message ORDER BY messages.created_at DESC LIMIT 1
So you need first order the records based on some column and then return the first record of that list.
$cart_data = ScCart::orderBy('created_at', 'asc')->first();
$cart_data = ScCart::orderBy('created_at', 'desc')->first();
This will work for first and last record created in that table.

Query Builder raw sub query is not working

I'm having Problem running this code.It says:
Syntax error or access violation: 1064 You have an error in your SQL
syntax.
I don't know if this is coming form subquery.Is it correct to write subquery like this?
$result = DB::table('grievance_redress_info')
->select(
'complainer_name',
'phone',
'complaint_date',
'address',
'complaintSub.name_en',
'resolve_action_date',
DB::raw("(SELECT grievance_history.status
FROM grievance_history
WHERE grievance_history.grievance_id=grievance_redress_info.id
ORDER BY grievance_history.id DESC LIMIT 1) AS current_status")
)
->leftJoin("common_labels AS
complaintSub",'grievance_redress_info.complaint_subject_id','=','complaintSub.id')
->get();
I think you can do something like this
$grievance_redress_info = DB::table('grievance_redress_info')
->select(
'complainer_name',
'phone',
'complaint_date',
'address',
'complaintSub.name_en',
'complaintMeans.name_en',
'resolve_action_date');
$result = DB::table('grievance_history')
->leftJoinSub($grievance_redress_info, 'grievance_redress_info', function ($join) {
$join->on('grievance_history.grievance_id', '=', 'grievance_redress_info.id');
})->select('grievance_history.status')->get();
you can check the docs for more
I hope this works!

laravel simple query builder (join & where case)

i have 2 table (product & type)
produk table
-id
-kode_produk
-nama_produk
-id_jenis_produk
and
jenis table
- id
- jenis_item
i wanna access database jenis_item from jenis tablewith query builder
so far i already try
$selectProduk = DB::table('produk')->where('id', $id)->join('jenis', 'produk.id_jenis_produk', '=', 'jenis.id')->first();
and something like this
$selectProduk = DB::table('produk')
->join('jenis', function($join) {
$join->on('produk.id_jenis_item', '=', 'jenis.id')
->where('produk.id', $id); // line 86 (error)
})->first();
but still failed with message error from laravel logs
exception 'ErrorException' with message 'Undefined variable: id' in C:\xampp\htdocs\itklan\app\controllers\ProdukController.php:86
where i'm missing?
#Thomas Kim
i get another error
exception 'ErrorException' with message 'Missing argument 3 for Illuminate\Database\Query\JoinClause::where(), called in C:\xampp\htdocs\itklan\app\controllers\ProdukController.php on line 86 and defined' in C:\xampp\htdocs\itklan\vendor\laravel\framework\src\Illuminate\Database\Query\JoinClause.php:87
line 87 :
$selectProduk = DB::table('produk')
->join('jenis', function($join) use($id) {
$join->on('produk.id_jenis_item', '=', 'jenis.id')
->where('produk.id', $id);
})->first(); //line 87
This is how PHP closures work. In order to use $id, the closure must inherit the variable from the parent scope by using the use keyword. For example:
$selectProduk = DB::table('produk')
->join('jenis', function($join) use($id) { // Check this line
$join->on('produk.id_jenis_item', '=', 'jenis.id')
->where('produk.id', '=', $id);
})->first();
Closures may also inherit variables from the parent scope. Any such variables must be passed to the use language construct.
Source: http://php.net/manual/en/functions.anonymous.php
Edit:
Also, looks like with Laravel's JoinClause, you need to be specific about your operators. Normally, you can do this:
->where('produk.id', $id);
And Laravel adds an equal operator for you. However, for join clauses, this will not work. You need to specify the operator.
->where('produk.id', '=', $id);

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

Laravel Eloquent Select CASE?

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();