Laravel 4 - Join table but only latest row - laravel

I have 2 tables : Quotes, Responses.
In a datatable , I show quotes, and for each row, I show a column count of responses. I want now to show date of latest response, but I'm blocked :(
Here is my code:
$quotes = Quote::select('Quotes.*', DB::raw('COUNT(Responses.id) as total_responses') )
->leftjoin('Responses', function($join)
{
$join->on('Responses.quote_id', '=', 'Quotes.id')
->where('Responses.state', '!=', '0');
})
->groupby('Quotes.id');
Is it possible to add another left join with same table, with custom query to select only latest row?
Thanks for helping

You can use the raw MAX function. Assuming your date is stored Responses.date, the code will look like this
$quotes = Quote::select('Quotes.*', DB::raw('COUNT(Responses.id) as total_responses'), DB::raw('MAX(CAST(Responses.date AS CHAR)) as latest') )
->leftjoin('Responses', function($join) {
$join->on('Responses.quote_id', '=', 'Quotes.id')
->where('Responses.state', '!=', '0');
})
->groupby('Quotes.id');
It first has to be cast as a char because of a mysql bug https://bugs.mysql.com/bug.php?id=54784

What you need is to include Responses.created_at in your select command and filter it using same column. i.e.
$quotes = Quote::select('Quotes.*', 'Responses.created_at as last_response_date', DB::raw('COUNT(Responses.id) as total_responses'))
->leftjoin('Responses', function($join)
{
$join->on('Responses.quote_id', '=', 'Quotes.id')
->where('Responses.state', '!=', '0');
})
->groupby('Quotes.id')->orderBy('Responses.created_at', 'desc');

Related

Eloquent - Join a Subquery

I have a complicated query that I would like to translate either in Eloquent ORM or with the Query Builder for a Laravel site, but I can't do it, can someone help me?
Here is my SQL query
SELECT opp_id, risk_study.rst_id, risk_study.rst_status
FROM opportunity
LEFT JOIN risk_study ON risk_study.rst_id =
(SELECT risk_study_quote_vehicle.rst_id
FROM risk_study_quote_vehicle
INNER JOIN quote_vehicle ON quote_vehicle.quv_id = risk_study_quote_vehicle.quv_id
INNER JOIN quote ON quote.quo_id = quote_vehicle.quo_id
WHERE quote.opp_id = opportunity.opp_id
ORDER BY risk_study_quote_vehicle.rst_id DESC
LIMIT 0,1)
WHERE 1 = 1
AND opportunity.per_id_process = '5'
AND opportunity.opp_locked = '1'
Here is my solution.
But this query does not retrieve values from the risk_study table.
$opportunities = Opportunity::select('opp_id', 'risk_study.rst_id', 'risk_study.rst_status')
->leftJoin('risk_study', function ($join) {
$join->on('risk_study.rst_id', '=', DB::raw('"SELECT risk_study_quote_vehicle.rst_id FROM risk_study_quote_vehicle INNER JOIN quote_vehicle ON quote_vehicle.quv_id = risk_study_quote_vehicle.quv_id INNER JOIN quote ON quote.quo_id = quote_vehicle.quo_id WHERE quote.opp_id = opportunity.opp_id ORDER BY risk_study_quote_vehicle.rst_id DESC LIMIT 0,1"'));
})
->where([
['per_id_process', 5],
['opp_locked', 1],
])
->get();
Finally, I wrote the query and it works ! Thanks !
$opportunities = Opportunity::query()
->select(
'opp_id',
'risk_study.rst_id',
'risk_study.rst_status'
)
->from('opportunity')
->leftJoin('risk_study', function ($join) {
$join->where('risk_study.rst_id', function ($sub) {
$sub->select('risk_study_quote_vehicle.rst_id')
->from('risk_study_quote_vehicle')
->join('quote_vehicle', 'quote_vehicle.quv_id', 'risk_study_quote_vehicle.quv_id')
->join('quote', 'quote.quo_id', 'quote_vehicle.quo_id')
->whereColumn('quote.opp_id', 'opportunity.opp_id')
->orderByDesc('risk_study_quote_vehicle.rst_id')
->limit(1);
});
})
->where('opportunity.per_id_process', '5')
->where('opportunity.opp_locked', '1')
->get();
You should be able to use a Closure as the second parameter of where() inside your join Closure.
I don't think Laravel's query builder supports the LIMIT 0,1 statement.
I don't know why you need WHERE 1 = 1, but you should be able to use whereRaw for that.
When you're done, the result looks very alike a formatted SQL query.
$opportunities = Opportunity::query()
->select(
'opp_id',
'risk_study.rst_id',
'risk_study.rst_status'
)
->from('opportunity')
->leftJoin('risk_study', function ($join) {
$join->where('risk_study_quote_vehicle.rst_id', function ($sub) {
$sub->select('risk_study_quote_vehicle.rst_id')
->from('risk_study_quote_vehicle')
->join('quote_vehicle', 'quote_vehicle.quv.id', 'risk_study_quote_vehicle.quv_id')
->join('quote', 'quote.quo_id', 'quote_vehicle.quo_id')
->where('quote_opp_id', 'opportunity.opp_id')
->orderByDesc('risk_study_quote_vehicle.rst_id')
->limit(1);
});
})
->whereRaw('1 = 1')
->where('opportunity.per_id_process', '5')
->where('opportunity.opp_locked', '1')
->get();

Laravel JOIN with JSON string

I have two tables in Laravel, one is the comment table, and the second is the users table. In the comment table, I have this type of data.
For this comment table, I want to match the tags column's userid in JSON, so how can we join that userid with the user's table? here is what I tried, but that is not working as expected.
$messages = TopicComment::where('user_id', $currentUserId)
->join("users", "users.id", "=", "users.id")
->(function ($query) {
$query->whereJsonContains('tags.userid', users.id);
})
->
->get()->toArray();
with this package you can create a relation via a json field
https://github.com/staudenmeir/eloquent-json-relations
First, there seem to be a number of errors in your code.
Judging from the DB schema, there is no user_id column in your comments table and so, ::where('user_id', $currentUserId) will not work.
A similar issue occurs in your join statement. You're joining on "users.id","=","users.id" which is the same column in the same table.
There's no method called in the line with function($query). Ideally, should be a where clause.
Correct usage of whereJsonContains would be:
$query->whereJsonContains('tags', ['userid' => $currentUserId]);
Rouge arrow after that line.
And so, your final result after correcting the changes should look like:
use Illuminate\Support\Facades\DB;
...
$messages = TopicComment::join('users', 'users.id', DB::Raw("CAST(comments.tags->'$.userid' AS UNSIGNED)"))
->where(function ($query) use ($currentUserId) {
$query->whereJsonContains('tags', ['userid' => $currentUserId]);
})
->get()
->toArray();
I think the only way to extract is to use json tables.
DB::select(DB::raw("
SELECT document_types.*, jst.name
FROM document_types,
JSON_TABLE(settings, '$[*]' COLUMNS (
`userid` int(11) PATH '$.userid',
`name` varchar(255) PATH '$.name'
)) jst
inner join users on jst.userid = users.id WHERE users.id = :id"
,['id' => $currentUserId]))->get()
credit: https://dba.stackexchange.com/questions/306938/extract-json-object-inside-of-an-json-array-then-search-base-on-id
Unfortunately I don't have json functions on my mysql so the code will probably fail, maybe at least it'll help get you on the right track.
You can try this way...
eg:
<?php
$comments = DB::table('topic_comments')
->join('users', 'users.id', '=', 'topic_comments.tags->userid')
->select('topic_comments.*', 'users.name')
->get();

Laravel 8 - How I do where clause in table added with join

Hi I want to know how can i do this query in Laravel 8 , I tried adding the join clause but not work as expected, i need join clause? Or maybe there is another form to do it. I search others examples but i donĀ“t see anythat help me. The query is the next:
DB::table('escandallo_p as esc')
->select("esc.material", "esc.referencia", "esc.ancho", "esc.proveedor", "esc.punto",
"esc.precio", "esc.consumo", "esc.veces", "esc.001", "esc.002", "esc.003", "esc.004",
"esc.005", "esc.006", "esc.007", "esc.008", "esc.009", "esc.010", "esc.011", "esc.um", "esc.merma", "esc.importe", "esc.tipo", "esc.xtalla", "esc.fase",
DB::raw("(select anulado from prototipos_p as p where p.prototipo = '".$scandal[0]->prototipo."' and p.tipo = 'c' and p.referencia = esc.referencia )"),
// ignore
//original query "(select anulado from prototipos_p as p where p.prototipo = ",$request->prototipo," and p.tipo = 'c' and p.referencia = esc.referencia ) as 'anulado'",
// "(select clase from prototipos_p as p where p.prototipo = ",$request->prototipo," and p.tipo = 'c' and p.referencia = esc.referencia ) as 'clase'")
//Converted query ->select('pro.anulado')->where('pro.prototipo', $request->prototipo)
// ->where("p.prototipo", "=", $request->prototipo)
->where("esc.id_escandallo", "=", $request->id_escandallo)
->where("esc.id_version", "=", $request->version)
->orderBy("id","asc")
->get();
!!!! I need to pass the esc.referencia to the sub select query
The second select is the conversion of the select inside "" ( i know this is wrong is only for explain it).
Thank you in advance for any suggestion.
Best regards
EDIT: I can solve my problem with DB::raw, but if anyone know others methos are welcome!
You need to pass callback to the join query to add the extra query to the laravel's join method,
Example from Laravel Doc:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
It is explained in Laravel's doc, Advanced Join Clauses
There is Subquery support too Subquery Joins,
Eg:
$latestPosts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
->where('is_published', true)
->groupBy('user_id');
$users = DB::table('users')
->joinSub($latestPosts, 'latest_posts', function ($join) {
$join->on('users.id', '=', 'latest_posts.user_id');
})
->get();
These two might help you to achieve what you are trying
After test joins, joinSub, whereIn and other forms of doing this, I solved my problem using the DB::raw():
DB::table('escandallo_p as esc')
->select('parameters',....,
DB::raw("(SELECT column //(ONLY ONE)
FROM table
WHERE column = '".$parameter."' ...) AS nombre"),
)
->where('column', "=", $parameter)
->orderBy("id","asc")
->get();

Laravel Query Builder Foreach Loop how do I reference a field that exists in both join tables

The id field in the foreach loop exists in both of the tables that I am joining, I need to reference it to one table only (ie. program_types.id) in the foreach loop:
$program_details = DB::table('program_allocation')
->where('twilio_wa_from_no', '=', $tophonenumber)
->where('twilio_sid' , $account_sid)
->join('program_types', 'program_allocation.program_type', '=', 'program_types.id')
->get();
foreach ($program_details as $program) {
$program_allocation_id = $program->id;
}
You can use select('program_allocation.*', 'program_types.id AS program_type_id') to specify which columns of which tables included in query you want to use.
$program_details = DB::table('program_allocation')
->where('twilio_wa_from_no', '=', $tophonenumber)
->where('twilio_sid', $account_sid)
->join('program_types', 'program_allocation.program_type', '=', 'program_types.id')
->select('program_allocation.*', 'program_types.id AS program_type_id')
->get();
You can check it on official Laravel documentation: https://laravel.com/docs/9.x/queries#inner-join-clause
Select field and give one of the join table id an alias
$program_details = DB::table('program_allocation')
->join('program_types', 'program_allocation.program_type', '=', 'program_types.id')
->select('program_types.*', 'program_allocation.id as allocationID', )
->where('twilio_wa_from_no', '=', $tophonenumber)
->where('twilio_sid' , $account_sid)
->get();

How can I write Laravel eloquent query (inner query) for this plain SQL query

SELECT *
FROM (
SELECT *
FROM appointments
WHERE `date` <= Curdate()
) `t`
WHERE `t`.`end_time` <= current_time
How can I write a Laravel eloquent equivalent query for this SQL query?
If you want to query:
all past appointments (from start to yesterday, based on date field) +
all today appointments that have end_time not past (or exactly now) for today
And assuming you have a proper Model for the appointment table you could try something like :
Appointments::where('appointments.date', '<', Carbon::now()->toDateString())
->orWhere(function ($query) {
$query->where('appointments.date', Carbon::now()->toDateString())
->where('appointments.end_time', '<=', Carbon::now()->toTimeString());
});
You may need to test the Carbon format used in where clauses to be sure it matches your database storage format, and the query return expected results.
I am not sure whether this suit you, you can try it:
Appointment::whereIn('id', function($query) {
$query->select('id')
->from('appointment')
->where('date', '<=', DB::raw('CURDATE()'));
})
->where('end_time', '<=', DB::raw('CURRENT_TIME()'));
Try this i hope you got your solution .
Appointment::whereExists(function ($query){ $query->selectRaw(1) ->from((new
Appointment())->getTable()) ->whereDate("date",'<=',now()->format('Y-m-d')); })-
>whereDate("end_time",'<=',now()->format('H:i:s'))->get()

Resources