Count all the grouped rows with Eloquent - laravel

I'm trying to count all the grouped rows but have no clue how to do it, if possible, with Eloquent.
My query looks like this:
SELECT COUNT(*) FROM (SELECT date FROM `reports` WHERE project_id = X GROUP BY `date`) as t1
As of now I'm using raw database queries:
DB::select(DB::raw("SELECT COUNT(*) as total FROM (SELECT date FROM `" . (new Report)->getTable() . "` WHERE project_id = " . ((int) $this->project->id) . " GROUP BY `date`) as t1"))[0]->total
Is it possible to achieve this with Eloquent, or at least make the PHP "call" prettier?

You can use the Query Builder:
I'd do something along this (I don't think you need that subquery):
Report::where('project_id', $this->project->id)
->count(DB::raw('DISTINCT date'));

Related

How to order by heading and then the description

I have a table with heading and description when user searches the blog it should list first all the heading and then the description currently it is ordering by date created. And search should be case insenstive
$SQL = "(SELECT * FROM {$this->blogs} WHERE Lower(heading) LIKE '%" .strtolower($query) . "%' )
UNION
(SELECT * FROM {$this->blogs} WHERE Lower(description) LIKE '%" . strtolower($query) ."%')";
$run = $this->db->query( $SQL );
Query1
SELECT * FROM tbl_wonderblogs WHERE LOWER(heading) LIKE '%indian army amfc%' ) UNION (SELECT * FROM tbl_wonderblogs WHERE LOWER(description) LIKE '%indian army amfc%'
Query2
SELECT * FROM tbl_wonderblogs WHERE LOWER(heading) LIKE '%indian army afmc%' ) UNION (SELECT * FROM tbl_wonderblogs WHERE LOWER(description) LIKE '%indian army afmc%'
What is difference between query1 and query2 in which query 1 yeild results and query 2 does not yeild any results
The results are sorted by date created because of this code
$this->db->order_by('createdon DESC');
It asks that output is sorted by the contents of the createdon field in descending order.
I think you will find the following will make the output sort the way you want.
$this->db->order_by('description DESC, heading DESC');
There are a couple of different ways to use the order_by() method as shown in the documentation. The following will produce the same result as the previous code.
$this->db->order_by('description' 'DESC');
$this->db->order_by('heading', 'DESC');

Laravel query using group by and where does not work

This is a query that I have in raw sql.
DB::select('SELECT bldgs.name as building , floors.name as floor, areas.name as area, locations.area_id ,count(reqs.location_id) as occupied FROM `reqs` '
. 'JOIN locations ON locations.id = location_id '
. 'JOIN areas ON areas.id = area_id '
. 'JOIN floors ON floors.id = areas.floor_id'
. ' JOIN bldgs ON bldgs.id = bldg_id '
. 'WHERE `status`=2 and (DATE_FORMAT(start_date,"%Y-%m")<= "'.$dateFrom.'" AND DATE_FORMAT(end_date,"%Y-%m")>="'.$dateTo.'") group by locations.area_id, areas.name, floors.name, bldgs.name' );
And this is one of many attempts to make it work in Laravel elequent instead of raw.
Req::select('bldgs.name as building',DB::raw('count(location_id) as count_occupied'))
->join('locations','locations.id','=','location_id')
->join('areas','areas.id','=','locations.area_id')
->join('floors','floors.id','=','areas.floor_id')
->join('bldgs as bl','bl.id','=','floors.bldg_id')
->where('reqs.status','=', '2')
->where('start_date','<=', $date)
->where('end_date','>=', $date)
->groupBy('bldgs.name')
I need to understand why the second way gives mysql error and refuses to run the query above. Is is a mistake in my code or is this normally not possible in using eloguent to group by like this except in raw mysql string?
This is the error I get.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'bldgs.name' in 'field list' (SQL: select `bldgs`.`name` as `building`, count(location_id) as count_occupied from `reqs` inner join `locations` on `locations`.`id` = `location_id` inner join `areas` on `areas`.`id` = `locations`.`area_id` inner join `floors` on `floors`.`id` = `areas`.`floor_id` inner join `bldgs` as `bl` on `bl`.`id` = `floors`.`bldg_id` where `reqs`.`status` = 2 and `start_date` <= 2018-10 and `end_date` >= 2018-10 group by `bldgs`.`name`)
As the error states, you don't have a bldgs.name column. You named the bldgs table bl when you joined it.
Rename your references from bldgs.name to bl.name.

Is there an alternative to MySQL Field() function in VFP?

I have a multi fields table with a Countries column. I like the results from a query to be ordered by a particular country first and the rest alphabetically. In MySQL I would do something like:
Select * from myTable Order By Field(Countries,'Italy'),Countries
In Visual-FoxPro I have tried indexing the Cursor created by this query:
Select * from myTable Order By Countries
Index on Countries<>'Italy' TAG test
This would display all results for 'Italy' first, but leave the rest in an unpredictable order.
How to achieve this in Visual-FoxPro?
In VFP you can do it with something like this:
SELECT * FROM myTable WHERE Countries='Italy' ;
UNION ALL ;
SELECT * FROM (SELECT * FROM myTable WHERE Countries<>'Italy' ORDER BY Countries) as secsel
It does order by "if countries is not Italy first then Italy", Countries. Right?
In VFP you can use IIF(). ie:
Select *, iif(Countries == 'Italy', 1, 0) as CItaly ;
from myTable :
Order By CItaly,Countries
Note: If you want to do this via an index then you can use a composite index like:
index on iif(Countries = 'Italy', '1', '0') + Countries tag myCountry

Converting a raw query to Laravel query builder

I have the following MySQL query which fetches a list of the last 9 authors to write a post and lists them in order of the date of the last post they wrote.
It's working properly but I'd like to re-write it using the Laravel Query Builder. Here is the query at the moment:
$authors = DB::select("
SELECT
`a`.`id`,
`a`.`name`,
`a`.`avatar`,
`a`.`slug` AS `author_slug`,
`p`.`subheading`,
`p`.`title`,
`p`.`slug` AS `post_slug`,
`p`.`summary`,
`p`.`published_at`
FROM
`authors` AS `a`
JOIN
`posts` AS `p`
ON `p`.`id` =
(
SELECT `p2`.`id`
FROM `posts` AS `p2`
WHERE `p2`.`author_id` = `a`.`id`
ORDER BY `p2`.`published_at` DESC
LIMIT 1
)
WHERE
`a`.`online` = 1
ORDER BY
`published_at` DESC
LIMIT 9
");
I understand the basics of using the query builder, but there doesn't appear to be anything in the Laravel docs that allows for me to JOIN a table ON a SELECT.
Can anyone suggest a way that I can write this query using the Laravel Query builder, or perhaps suggest a way that I can rewrite this query to make it easier to structure with the query builder?
Try to do like this
$data = DB::table('authors')
->select(
'a.id',
'a.name',
'a.avatar',
'a.slug AS author_slug',
'p.subheading',
'p.title',
'p.slug AS post_slug',
'p.summary',
p.published_at')
->from('authors AS a')
->join('posts AS p', 'p.id', '=', DB::raw("
(
SELECT p2.id FROM posts AS p2
WHERE p2.author_id = b.id
ORDER BY p2.published_at
DESC LIMIT 1
)"))
->where('a.online', 1)
->limit(9)
->orderBy('p.published_at', 'desc')
->get();

How do I return last n records in the order of entry

From Laravel 4 and Eloquent ORM - How to select the last 5 rows of a table, but my question is a little different.
How do I return last N records ordered in the way they were created (ASC).
So for example the following records are inserted in order:
first
second
third
fourth
fifth
I want a query to return last 2 records
fourth
fifth
Laravel Offset
DB::table('users')->skip(<NUMBER Calulation>)->take(5)->get();
You can calculate N by getting the count of the current query and skipping $query->count() - 5 to get the last 5 records or whatever you wanted.
Ex
$query = User::all();
$count = ($query->count()) - 5;
$query = $query->skip($count)->get();
In pure SQL this is done by using a subquery. Something like this:
SELECT * FROM (
SELECT * FROM foo
ORDER BY created_at DES
LIMIT 2
) as sub
ORDER BY created_at ASC
So the limiting happens in the subquery and then in the main query the order by is reversed. Laravel doesn't really have native support for subqueries. However you can still do it:
$sub = DB::table('foo')->latest()->take(2);
$result = DB::table(DB::raw('(' . $sub->toSql() . ') as sub'))
->oldest()
->get();
And if you use Eloquent:
$sub = Foo::latest()->take(2);
$result = Foo::from(DB::raw('(' . $sub->toSql() . ') as sub'))
->oldest()
->get();
Note the latest and oldest just add an orderBy('created_at) with desc and asc respectively.

Resources