How to display query assembled by ORM? - php

How to display query assembled by ORM ?
Example: SELECT article.id AS article:id, article.name AS article:name
I'm using the code below:
$query=DB::select('categories.*',
array(DB::expr('COUNT(categories.id)'), 'total'),
array(DB::expr('MIN(displays.price)'), 'min_price'),
array(DB::expr('MAX(displays.price)'), 'max_price'),
array(DB::expr('SUM(displays.is_offer)'), 'is_offer')
)
->from('categories')
->join('category_products', 'INNER')
->on('categories.id', '=', 'category_products.category_id')
->join('displays', 'INNER')
->on('category_products.product_id', '=', 'displays.product_id')
->where('displays.active', '>=', 1)
->group_by('categories.id')
->order_by('parent')
->order_by('total', 'desc');

Let's see, you're using DB::select() which returns a Database_Query_Builder_Select instance. In the doc it says
Database query builder for SELECT statements. See Query Builder for usage and examples.
And if you do see, you'll see
echo Debug::vars((string) $query);
// Should display:
// SELECT `username`, `password` FROM `users` WHERE `username` = 'john'
which makes sense once you see the __toString() from Database_Query_Builder_Select.
So
echo (string) $query;
should give you the query.

Related

Laravel Query Builder returns no results while generated SQL works perfect

I am actively working on a laravel project and have ran into some issues with the Query Builder. I am trying to avoid using DB::Raw but it is looking like I may need to.
$query = app($this->model());
$query = $query->select(['last_name', 'first_name', 'birthday'])
->distinct()
->leftJoin('enrollments', 'students_meta.uid', '=', 'enrollments.student_uid')
->whereIn('enrollments.type', $types)
->where('enrollments.startdate', '<=', "'{$today}'")
->where(function ($join) use ($today) {
$join->where('enrollments.dropdate', '>=', "'{$today}'")
->orWhereNull('enrollments.dropdate');
});
// todo: add viewBy filter
$query = $query->where('birth_month', '=', Carbon::today()->month);
$query = $query->orderBy('last_name')->orderBy('first_name');
$models = $query->get();
The above query builder generates the following SQL :
SELECT distinct `last_name`, `first_name`, `birthday`
FROM `students_meta`
LEFT JOIN `enrollments` ON `students_meta`.`uid` = `enrollments`.`student_uid`
WHERE `enrollments`.`type` IN ('ACTIVE', 'active')
AND `enrollments`.`startdate` <= '2019-10-29'
AND (`enrollments`.`dropdate` >= '2019-10-29' OR `enrollments`.`dropdate` IS NULL)
AND `birth_month` = 10
ORDER BY `last_name` asc, `first_name` asc;
The generated SQL is perfect based on the old code I'm moving from and produces the expected results. If I move some things around, it seems I can get the query builder to return results, but they're not the correct ones. I've looked at other questions/answers about this kind of problem and tried multiple scenarios of moving the join/changing the where's around, still no luck.
Any suggestions? (other than taking the generated sql and running it in DB::Raw()
$query = $query->orderBy('last_name')->orderBy('first_name')->get();
Your query worked fine but you didn't output it.
You can also use ->get()->toArray(); to retrieve the data in array format
Remove your quotes from around $today. The third (or second, if you eliminate the comparison operator) parameter of the where clause sends the values as a parameter in a prepared statement . So
"'{$today}'"
would look like this in a straight query:
where enrollments.startdate <= "'2019-10-29'"
So change your query to
->where('enrollments.startdate', '<=', $today)
Make sure you remove the quotes from all instances like this in your query.

Laravel Eloquent - How to group conditions

I'm using the following eloquent statement
Title::where('word', 'lovers')
->orWhere('word', 'lover')
->where('domain', $resultFromFirstKeyword->domain)
->get();
Which I can see through the SQL logger produces the following SQL
SELECT * FROM `title`
WHERE `word` = 'lovers'
OR `word` = 'lover'
AND `domain` = 'www.texasbirdlovers.com'
However the SQL that I would like to produce is
SELECT * FROM `title`
WHERE (`word` = 'lovers' OR `word` = 'lover')
AND `domain` = 'www.texasbirdlovers.com'
How would I achieve this?
This should work:
Title::whereIn('word', ['lovers', 'lover'])
->where('domain', $resultFromFirstKeyword->domain)
->get();
If, however, you want to combine them exactly like you said, try this:
Title::where(function($query) {
$query->where('word', 'lovers')
->orWhere('word', 'lover');
})
->where('domain', $resultFromFirstKeyword->domain)
->get();
Just group your query in a where clause
Title::where(function($q){
$q->where('word', 'lovers')->orWhere('word', 'lover');
})->where('domain', $resultFromFirstKeyword->domain)->get();
Try
Title::where('domain', $resultFromFirstKeyword->domain)
->where(function($query) {
return $query
->where('word', '=', 'lovers')
->orWhere('word', '=', 'word');
})->get();
Try the following:
Title::where(function($query) {
return $query
->where('word', 'lover')
->orWhere('word', 'lovers');
})
->where('domain', $resultFromFirstKeyword->domain)
->get();

convert SQL query to query builder style

Im trying days to understand how I can convert a SQL query to a query builder style in laravel.
My SQL query is:
$tagid = Db::select("SELECT `id` FROM `wouter_blog_tags` WHERE `slug` = '".$this->param('slug')."'");
$blog = Db::select("SELECT *
FROM `wouter_blog_posts`
WHERE `published` IS NOT NULL
AND `published` = '1'
AND `published_at` IS NOT NULL
AND `published_at` < NOW()
AND (
SELECT count( * )
FROM `wouter_blog_tags`
INNER JOIN `wouter_blog_posts_tags` ON `wouter_blog_tags`.`id` = `wouter_blog_posts_tags`.`tags_id`
WHERE `wouter_blog_posts_tags`.`post_id` = `wouter_blog_posts`.`id`
AND `id`
IN (
'".$tagid[0]->id."'
)) >=1
ORDER BY `published_at` DESC
LIMIT 10
OFFSET 0");
Where I now end up to convert to the query builder is:
$test = Db::table('wouter_blog_posts')
->where('published', '=', 1)
->where('published', '=', 'IS NOT NULL')
->where('published_at', '=', 'IS NOT NULL')
->where('published_at', '<', 'NOW()')
->select(Db::raw('count(*) wouter_blog_tags'))
->join('wouter_blog_posts_tags', function($join)
{
$join->on('wouter_blog_tags.id', '=', 'wouter_blog_posts_tags.tags_id')
->on('wouter_blog_posts_tags.post_id', '=', 'wouter_blog_posts.id')
->whereIn('id', $tagid[0]->id);
})
->get();
I have read that I can't use whereIn in a join. The error i now get:
Call to undefined method Illuminate\Database\Query\JoinClause::whereIn()
I realy dont know how I can convert my SQL to query builder. I hope when I see a good working conversion of my query I can understand how I have to do it next time.
This work for me:
DB::table('wouter_blog_posts')
->whereNotNull('published')
->where('published', 1)
->whereNotNull('published_at')
->whereRaw('published_at < NOW()')
->whereRaw("(SELECT count(*)
FROM wouter_blog_tags
INNER JOIN wouter_blog_posts_tags ON wouter_blog_tags.id = wouter_blog_posts_tags.tags_id
WHERE wouter_blog_posts_tags.post_id = wouter_blog_posts.id
AND id
IN (
'".$tagid."'
)) >=1")
->orderBy('published_at', 'desc')
->skip(0)
->take(10)
->paginate($this->property('postsPerPage'));
The following Query Builder code will give you the exact SQL query you have within your DB::select:
DB::table('wouter_blog_posts')
->whereNotNull('published')
->where('published', 1)
->whereNotNull('published_at')
->whereRaw('`published_at` < NOW()')
->where(DB::raw('1'), '<=', function ($query) use ($tagid) {
$query->from('wouter_blog_tags')
->select('count(*)')
->join('wouter_blog_posts_tags', 'wouter_blog_tags.id', '=', 'wouter_blog_posts_tags.tags_id')
->whereRaw('`wouter_blog_posts_tags`.`post_id` = `wouter_blog_posts`.`id`')
->whereIn('id', [$tagid[0]->id]);
})
->orderBy('published_at', 'desc')
->skip(0)
->take(10)
->get();
The subquery condition had to be reversed because you can't have a subquery as the first parameter of the where method and still be able to bind the condition value. So it's 1 <= (subquery) which is equivalent to (subquery) >= 1. The query generated by the above code will look like this:
SELECT *
FROM `wouter_blog_posts`
WHERE `published` IS NOT NULL
AND `published` = 1
AND `published_at` IS NOT NULL
AND `published_at` < Now()
AND 1 <= (SELECT `count(*)`
FROM `wouter_blog_tags`
INNER JOIN `wouter_blog_posts_tags`
ON `wouter_blog_tags`.`id` =
`wouter_blog_posts_tags`.`tags_id`
WHERE `wouter_blog_posts_tags`.`post_id` =
`wouter_blog_posts`.`id`
AND `id` IN ( ? ))
ORDER BY `published_at` DESC
LIMIT 10 offset 0
My process when creating more complex queries is to first create them and try them out in a SQL environment to make sure they work as indended. Then I implement them step by step with the Query Builder, but instead of using get() at the end of the query, I use toSql() which will give me a string representation of the query that will be generated by the Query Builder, allowing me to compare that to my original query to make sure it's the same.

running a mysql query containing division in laravel 5

I want to run this mysql query in Laravel 5 using the DB query :
// SELECT *, rating/number as total FROM `courses` order by total DESC;
This is what I tried :
$query = \DB::table('courses')->select('*');
$courses = $query->addSelect('rating/number as total')
->orderBY('total DESC')
->get();
but, rating/number is considered as a table column . The same thing happens when I tried it inside parenthesis (rating/number).
Any help?
$courses = \DB::table('courses')
->selectRaw('*, rating/number as total')
->orderBY('total', 'DESC')
->get();
Can you use Raw Expressions for it? Maybe something like this:
$courses = \DB::table('courses')
->select(DB::raw('*, (rating / number) as total'))
->orderBy('total DESC')
->get();

Convert SQL query to Eloquent Laravel

I have a sql query:
select `id` from `users`
where (
select count(*)
from `user_event` as `uev`
where `uev`.`leader_id` = `users`.`id`
) > 1
How can I convert it to Eloquent Laravel?
Assuming you have set up the relationship you can use the has() method for that:
$users = User::select('id')->has('events', '>', 1)->get();
If you want an array of users ids (since you're only selecting the id) you can also use lists():
$ids = User::has('events', '>', 1)->lists('id');
Since you asked, this would be an alternative method (not tested though)
User::where(DB::raw('1'), '<', function($q){
$q->from('user_event')
->where('user_event.leader_id', 'users.id');
})->get();

Categories