How to convert SQL into Laravel 5.2 Query Builder - eloquent

Hello I am very new to Laravel and am having a big problem converting the following MYSQL query into a Laravel Query Builder. I am using Laravel 5.2.
Here is the working MYSQL query:
select * from
(select b.id, SUM(v.value) as total
from blog_entries as b
ON v.votable_id = b.id AND v.votable_type = 'App\\BlogEntry'
LEFT JOIN votes as v
GROUP BY b.id
ORDER BY total desc)
AS Data where Data.total > 0;
Is it possible to utilise Eloquent to execute this query?
I have read through Laravels Query Builder Documentation and it has gone way over my head. Any help or pointers would be greatly appreciated.
Thanks for your time and help!

I have found an solution to translating the SQL into Laravel Query Builder form:
Working Using Laravel's Query Builder:
DB::table('blog_entries')
->select('blog_entries.id', DB::raw('SUM(votes.value) as total'))
->leftjoin('votes', function ($join) {
$join->on('votes.votable_id', '=', 'blog_entries.id')
->where('votes.votable_type', '=', 'App\BlogEntry');
})
->groupBy('blog_entries.id')
->having('total', '>', 0)
->orderBy('total', 'DESC')
->get();

Related

Doctrine query result is empty but the generated running query works in Postgres

I have a native query in Doctrine, which generate the right SQL, which runs in PostgreSQL. However the Doctrine returns null/empty results.
public count unReadedNotifications(User $user) {
$rsm = new ResultSetMapping();
$sql =
"SELECT count(ele->'status') FROM notification CROSS JOIN LATERAL jsonb_array_elements(items) status(ele) WHERE notification.id = ? and (ele->'status')::jsonb #> '1'";
$query = $this->getEntityManager()->createNativeQuery($sql,$rsm)->setParameter('1', $user->getNotification()->getId());
return $query->getSingleScalarResult();
}
This Doctrine native query returns null.
If I check the profiler I see the generated query is:
SELECT count(ele->'status') FROM notification CROSS JOIN LATERAL jsonb_array_elements(items) status(ele) WHERE notification.id = 21 and (ele->'status')::jsonb #> '1';
If I copy-paste this into pgAdmin it runs and it retrieve the desired "2".
So pgAdmin can gives me the right result, but Doctrine not.
Can somebody see, where and what went wrong?
Doctrine version: 2.6.3, Postgres is 10.

How to correctly use the querybuilder in order to do a subselect?

I would like to do a subselect in order to do the following postgresql query with the querybuilder:
SELECT i.* FROM internship i
WHERE EXISTS (SELECT iw.*
FROM internship_weeks iw
WHERE i.id = iw.internship)
Does anyone have an idea how to get the same result with queryBuilder? or maybe with DQL?
Thanks for the help !
As example, only for demonstrate HOW-TO use a subquery select statement inside a select statement, suppose we what to find all user that not yet have compile the address (no records exists in the address table):
// get an ExpressionBuilder instance, so that you
$expr = $this->_em->getExpressionBuilder();
// create a subquery
$sub = $this->_em->createQueryBuilder()
->select('iw')
->from(IntershipWeek::class, 'iw')
->where('i.id = iw.intership');
$qb = $this->_em->createQueryBuilder()
->select('i')
->from(Intership::class, 'u')
->where($expr->exists($sub->getDQL()));
return $qb->getQuery()->getResult();
Hope this help

ALL query in Ecto

I need to translate the following SQL to Ecto Query DSL.
SELECT otc.*
FROM users u
INNER JOIN one_time_codes otc ON u.id = otc.user_id
LEFT OUTER JOIN one_time_code_invalidations otci ON otci.one_time_code_id = otc.id
WHERE u.id = 3 AND
otc.code = 482693 AND
otci.inserted_at IS NULL AND
otc.inserted_at > all(SELECT otc.inserted_at
FROM one_time_codes otc2
WHERE otc2.user_id = 3) AND
otc.inserted_at > (now() - '180 seconds'::interval);
In the third AND statement of WHERE clause, notice there is an ALL query. Ecto seems to not have corresponding function in Ecto.Query.API.
How to apply such aggregate? What is the correct way to implement this, though it could be implemented by having a lookup on debug logs of the Ecto, do you have another idea (or suggestion)?
Thank you.
Ecto does not allow subqueries in expressions, and you're right that there's no all in Ecto's Query API, but you can use fragment like this:
where: ...
and otc.inserted_at > fragment("all(SELECT otc.inserted_at FROM one_time_codes otc2 WHERE otc2.user_id = ?", 3)
and ...

Laravel 5, Derived table in join clause?

I have this query:
SELECT * FROM blog
LEFT JOIN (
SELECT blog_id, AVG(value) as blog_rating FROM blog_ratings
GROUP BY (blog_id)
) T ON T.blog_id = blog.id;
I do not know how to write this with Eloquent.
For Example:
Blog::select("*")->leftJoin( /* Here goes derived table */ )->get()
How do I accomplish this?
I'd personally just use the fluent query builder, try this out and see how it works out:
DB::table('blog')
->select('*')
->leftJoin(DB::raw('(SELECT blog_id, AVG(value) as blog_rating FROM blog_ratings
GROUP BY (blog_id)
) as T'), function ($join) {
$join->on ( 'T.blog_id', '=', 'blog.id' );
})
->get();
You can always swap ->get() for ->toSql() to dump out the query and adjust if you see any mistakes.

Get result of raw SQL query in Laravel 5 Eloquent

I need help to build a Laravel query from my raw SQL Query. I tried many way and did not find my Luck. Can anybody help me? My Raw SQL code is given bellow.
SELECT exams. * , count( question_details.exam_id ) AS qus_enter
FROM exams
INNER JOIN question_details ON exams.id = question_details.exam_id GROUP BY exams.id
This is what I've tried:
$examListsID = DB::table('exams')
->join('question_details', function($join) {
$join->on('exams.id', '=', 'question_details.exam_id as qus_enter');
})
->whereraw('count(qus_enter) = exams.total_question')
->select('exams.id as examID','qus_enter','exams.total_question')
->count('qus_enter')
->groupby('exams.id')
->get();
$examLists = Addexam::where('id','=',$examListsID->examID)
And I Get this Error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as qus_enter where count(qus_enter) = exams.total_question' at line 1 (SQL: select count(qus_enter) as aggregate from exams inner join question_details on exams.id = question_details.exam_id as qus_enter where count(qus_enter) = exams.total_question)
$result = DB::table('exams')->join('question_details','exams.id','=','question_details.exam_id')->select([
exams.*,
DB::raw('count( question_details.exam_id ) AS qus_enter')
])->GroupBy('exams.id')->get()
Hope this helps
DB::listen(function ($data) {
var_dump($data->bindings);
dd($data->sql);
});