Select the most recent record with groupby in Laravel - php

I have two tables entries similar as follows:
gym_clients
+---------+---------+-----------------+
| id | first_name| last_name |
+---------+-----------+---------------+
| 1 | Name 1 | Last 1 |
| 2 | Name 2 | Last 2 |
+---------+-----------+---------------+
gym_client_purchases
+---------+---------+-----------------+
| id | client_id | purchase_date |
+---------+-----------+---------------+
| 15 | 1 | 2018-04-01 |
| 16 | 1 | 2018-05-01 |
| 17 | 2 | 2018-05-01 |
+---------+-----------+---------------+
I want to group by the purchases of each client and show the latest.
I tried this query but the groupby shows me the oldest purchase (id 15).
any ideas?
$this->data['latestSubscriptions'] = GymPurchase::select('first_name', 'last_name', 'gym_client_purchases.*')
->leftJoin('gym_clients', 'gym_clients.id', '=', 'client_id')
->groupBy('gym_client_purchases.client_id')
->orderBy('gym_client_purchases.purchase_date', 'desc')
->get();
Thanks in advance.

If you are explicitly calling the table names to specify their columns, isn't that supposed to be the same on the ON clause? on your code it's like this
$this->data['latestSubscriptions'] = GymPurchase::select('first_name', 'last_name', 'gym_client_purchases.*')
//client_id here isn't specified
->leftJoin('gym_clients', 'gym_clients.id', '=', 'client_id')
->groupBy('gym_client_purchases.client_id')
->orderBy('gym_client_purchases.purchase_date', 'desc')
->get();
It should be like this:
$this->data['latestSubscriptions'] = GymPurchase::select('first_name', 'last_name', 'gym_client_purchases.*')
->leftJoin('gym_clients', 'gym_clients.id', '=', 'gym_client_purchases.client_id')
->groupBy('gym_client_purchases.client_id')
->orderBy('gym_client_purchases.purchase_date', 'desc')
->get();
I tested your code, it should be working properly due to the orderby descending, I think just a little typo on your code snippets

First, when you use group by you have o specify in this clause the columns for which the query is gioing to group, so I suggest to you to try you query on sql engine.
You will have something like this
select first_name, last_name, A.*
from gym_client_purchases A
left Join gym_clients B on B.id = A.client_id
group by A.client_id
order By A.purchase_date desc
and you will notice that it doesn't work
Maybe what you want is something like this
select A.client_id, B.first_name, B.last_name, max(A.purchase_date)
from gym_client_purchases A
left Join gym_clients B on B.id = A.client_id
group by A.client_id, B.first_name, B.last_name
order By max(A.purchase_date) desc

Related

How can we use count() with conditional sql in select() of laravel?

I have two tables as shown below. I am using Laravel DB method to join this table. But I am not getting how can I get the count of marks of students as per failed or passed. 0-failed 1-passed.
Expected result:
1. Student Name
2. Student Id,
3. Count of failed based on student Id as count_failed
4. Total Marks based on student Id as total_marks
table students
`+----+-----------+
| id | name |
+----+-----------+
| 1 | John Doe |
| 2 | Mark P |
| 3 | Pen Henry |
+----+-----------+`
table students_marks:
+----+------------+-------+-----------+
| id | student_id | marks |is_failed |
+----+------------+-------+-----------+
| 1 | 1 | 55 | 0 |
| 2 | 2 | 44 | 1 |
| 3 | 1 | 11 | 1 |
| 4 | 2 | 10 | 0 |
| 5 | 2 | 11 | 1 |
| 6 | 2 | 20 | 0 |
+----+------------+-------+-----------+
Below is query which I used:
$users = DB::table('users')
->join('contacts', 'students.id', '=', 'students_marks.user_id')
->select('student.*')
->get();
I am unable to get how can we use count() with conditional SQL in select() of laravel?
Use conditional aggregation:
$users = DB::table('students s')
->leftJoin('students_mark sm', 's.id', '=', 'sm.user_id')
->groupBy('sm.id')
->select(DB::raw('s.id, s.name, SUM(sm.is_failed) AS num_failed, COUNT(sm.user_id) AS total_cnt'))
->get();
This corresponds to the following raw MySQL query:
SELECT
s.id,
s.name,
SUM(sm.is_failed) AS num_failed,
COUNT(sm.user_id) AS total_cnt
FROM students s
LEFT JOIN students_marks sm
ON s.id = sm.user_id
GROUP BY
s.id;
Note: It is acceptable in ANSI SQL to select the name field in the above GROUP BY query assuming that student#id is the primary key column for that table. If the above query gives an ONLY_FULL_GROUP_BY error, then simply add s.name to the GROUP BY clause.
$users = DB::table('users')
->join('contacts', 'students.id', '=', 'students_marks.user_id')
->select('student.*', DB::raw("count(students_marks.is_failed) as count")))
->where('status', '=', 0)
->get();
Try this.
If this is not clear or doesn't work refer this
Try this code snippet
$table = DB::table('students_marks');
$table = $table->select(
\DB::raw('SUM(if(is_failed = '0', 1, 0)) AS failed'),
\DB::raw('SUM(if(is_failed = '1', 1, 0)) AS passed'),
\DB::raw('SUM(marks) AS total'));
$table = $table->Join('students', 'students.id', '=', 'students_marks.student_id');
$table = $table->get();
Try this
$users = DB::table('students s')
->leftJoin('students_mark sm', 's.id', '=', 'sm.student_id')
->groupBy('s.id','s.name')
->selectRaw("s.id,s.name,SUM(sm.is_failed) AS count_failed,SUM(sm.marks) as total_marks")
->get();

Converting raw queries into laravel

I have this schema
product_categories
id | product_category
---------------------
1 | ABC
2 | DBC
3 | EBA
store_product_categories
id | category_id | store_id
------------------------
1 | 2 | 11
2 | 1 | 11
3 | 3 | 11
I have created a query in mysql work bench
SELECT pc.* FROM product_categories pc LEFT JOIN store_product_categories spc ON pc.category = pc.id AND spc.store_id = 11 WHERE spc.category IS NULL;
This query actually gets all those categories from product_categories table which are not present in store_product_categories.
Now I am really really confused how to build this is Laravel Eloq..
I did try this.
$exclusive_categories = Product_category::join('store_product_categories','store_product_categories.category_id','=','product_categories.id')
->where('store_product_categories.store_id','=',session('store_id'))
->where('store_product_categories.category_id','=','NULL')->get();
But this doesn't give me result
Since you're joining on two different columns, you need to pass that through a function/closure:
$exclusive_categories = Product_category::leftJoin('store_product_categories', function($join) {
$join->on('store_product_categories.category_id','=','product_categories.id')
->on('store_product_categories.store_id','=',session('store_id'));
})
->where('store_product_categories.store_id','=','NULL')->get();
I'm not sure if this is quite what you want. If you're looking for where store_id is NULL OR store_id = the session id, you can pass that through another closure/function.
$exclusive_categories = Product_category::leftJoin('store_product_categories spc', function ($join) {
$join->on('spc.category_id', '=', 'product_categories.id');
$join->on('spc.store_id', '=', \DB::raw(session('store_id')));
})
->whereNull('spc.category_id')
->get(['product_categories.*']);
$exclusive_categories = Product_category::leftJoin('store_product_categories','store_product_categories.category_id','=','product_categories.id')
->where('store_product_categories.store_id','=',session('store_id'))
->whereNull('store_product_categories.store_id')->get();
https://laravel.com/docs/5.3/queries

How to display latest unique record in mysql codeigniter

lets suppose i have 6 records in my table
id | mobile_no | date
-------------------------------------------
1 | 9999999999 | 11-11-2016
2 | 8888888888 | 12-11-2016
3 | 9999999999 | 13-11-2016
4 | 9999999999 | 16-11-2016
5 | 8888888888 | 20-11-2016
6 | 8888888888 | 22-11-2016
Now when i use distinct with mysql query i retrieve :-
id | mobile_no | date
-------------------------------------------
1 | 9999999999 | 11-11-2016
2 | 8888888888 | 12-11-2016
While i want to retrieve :-
id | mobile_no | date
-------------------------------------------
4 | 9999999999 | 16-11-2016
6 | 8888888888 | 22-11-2016
Please help me what query i have to use in codeigniter mysql for access above records??
below is my model query -
$this->db->select('*');
$this->db->from('miscall_records');
$this->db->distinct();
$this->db->group_by('mobnos');
$this->db->order_by("id", "desc");
if you want to use the dataset with the highest ID each, you have to use a different approach.
you have to select the highest IDs for each number first via a GROUP BY with the corresponding aggregation function MAX, and then join the table itself on those keys.
SELECT values.* FROM
(SELECT MAX(id) AS id FROM miscall_records GROUP BY mobile_no) AS keys
LEFT JOIN miscall_records AS values
ON keys.id = values.id
Your expected sql query is :
select a.id, a.mobile_no, a.date from miscall_records a
where a.id = (select max(b.id) from miscall_records b
where b.mobile_no = a.mobile_no) group by a.mobile_no
With Active Records is :
$this->db->select('a.id, a.mobile_no, a.date');
$this->db->from('miscall_records a');
$this->db->where('a.id = (select max(b.id) from miscall_records b where b.mobile_no = a.mobile_no)');
$this->db->group_by('a.mobile_no');
$query = $this->db->get();
Or use only max :
select max(a.id), a.mobile_no, a.date from miscall_records a group by a.mobile_no
Active records :
$this->db->select('max(a.id), a.mobile_no, a.date');
$this->db->from('miscall_records a');
$this->db->group_by('a.mobile_no');
$query = $this->db->get();
You can use group by clause to group values by mobile no. distinct keyword will not work here.

Laravel / Mysql groupby ordering

I have the command
SELECT * FROM
(SELECT * FROM episodes ORDER BY created_at DESC) and t1
GROUP BY serial_id
ORDER BY created_at DESC
which I will return series where the last episode added by created_at. But the problem is that when I had it on hosting everything worked but now I put it on the VPS server and there I'm always lists the first episode. If i add desc after group by serial_id it's work but it is not possible on laravel (-> groupBy ('serial_id'))
Shared hosting:
+---------+-------------+--------+
| id | serial_id | part |
+---------+-------------+--------+
| 8124 | 12 | s02e10 |
| 362 | 8 | s09e12 |
| 4673 | 9 | s01e12 |
| 871 | 4 | s03e24 |
+---------+-------------+--------+
My VPS:
+---------+-------------+--------+
| id | serial_id | part |
+---------+-------------+--------+
| 8124 | 12 | s01e01 |
| 362 | 8 | s01e01 |
| 4673 | 9 | s01e01 |
| 871 | 4 | s01e01 |
+---------+-------------+--------+
Thank you in advance for your help
Seems you have a lot of errors in your query.
missing a tablename between FROM and ORDER BY
SELECT * FROM (SELECT * FROM
-- ^^ where is the tablename ?
ORDER BY episodes created_at DESC) and t1 GROUP BY ORDER BY serial_id created_at DESC
-- ^^ missing comma, ^^ this 'and' seems in the wrong place and you havent't column for group by and in last another missing comma
try something like this:
SELECT * FROM ( SELECT *
FROM my_table ORDER BY episodes, created_at DESC) t1
GROUP BY my_column_for_group_by
ORDER BY serial_id, created_at DESC
In laravel you could assign the order direction using:
->orderBy('serial_id')
->orderBy('created_at', 'DESC')
Probably you will have to use RAW in this case: groupBy(DB::raw('serial_id desc'))
like below
DB::table( DB::raw("(SELECT * FROM episodes ORDER BY created_at DESC) and t1") )->groupBy(DB::raw('serial_id desc'))->orderBy('created_at', 'desc')->get();

Mysql - join 2 queries with limit

Im not very familiar with using 'join' in queries. I really tried solving this by my own, but it seems to be too hard.
I got 2 Tables:
Table 'users':
+-----------------+-----------------+
| member | online |
+-----------------+-----------------+
| mahran | 1 |
| peter | 1 |
| Jen | 1 |
| Steve | 0 |
+-----------------+-----------------+
Table 'tickets'
+-----------------+----------------+----------------+
| name | category | time |
+-----------------+----------------+----------------+
| mahran | silver | 1 |
| peter | blue | 1 |
| mahran | blue | 2 |
| peter | red | 3 |
| peter | green | 2 |
| Jen | silver | 1 |
+-----------------+----------------+----------------+
The chellange:
I need each member (users.member) who's online (users.online). The next thing is to get the category for each member (user.member = tickets.name) with the highest time (probably ORDER BY time DESC LIMIT 1).
So, for example:
Peter is online. Peters highest time is 3 at the position of category=red. So I want peter to show up in the result with his category 'red'. Mahran would show up with blue. Jen would get silver. And steve would be left out because he's not online.
I hope this was clear. In general I know how the queries would look like but theres no chance for me merging them together.
What needs to be merged:
SELECT member FROM users WHERE online = 1;
|
v for each member
SELECT category FROM tickets WHERE name=users.member ORDER BY time DESC.
So, any ideas how to solve this?
Here is a fiddle with a not working query: Click
You can do this easily with a correlated subquery:
select u.member,
(select t.category
from tickets t
where t.name = u.member
order by t.time desc
limit 1
) as MostRecentCategory
from users u
where u.online = 1;
This can make use of the following indexes: users(online, member) and ticket(member, time, category).
Here is the query you're looking for:
SELECT U.member
,T.category
FROM users U
INNER JOIN tickets T ON T.name = U.member
INNER JOIN (SELECT T2.name
,MAX(T2.time) AS [maxTime]
FROM tickets T2
GROUP BY T2.name) AS M ON M.name = T.name
AND M.maxTime = T.time
WHERE U.online = 1
The use of [name] to join the two tables is not a good practice, it's much better to use keys instead. But my query is just here to help you understanding the process of jointure.
Hope this will help you.
If i understand you correctly
SELECT DISTINCT users.member, tickets.category FROM tickets JOIN users ON users.member = tickets.name WHERE users.online = 1 ORDER BY tickets.time DESC
Can you make sql fiddle?
USE DISTINCT
stackoverflow.com/questions/11704012/mysql-distinct-join
try this
SELECT DISTINCT User.member,Ticket.category FROM users AS USER
INNER JOIN tickets AS Ticket ON (User.member = Ticket.name)
WHERE User.online = 1;
Sorry, but peter seems to be RED, It's time is 3. Don't you?
Depending on table definition, is not guaranteed to have one only result for each user.
For example, if peter has time 3 in two categories, you can get one different category depending of the SQL sorting method.
To be sure, tickets.Category and tickets.time must be in a unique key (both toghether, not a unike key for each field)
Assuming that, the Query could be this.
select t2.name, t2.category
from
tickets t2
INNER JOIN (Select
u.member, max(time)
from users u, tickets t
where
u.member = t.name
and u.online = 1
group by u.member
) as usermaxtime on t2.name = usermaxtime.member;

Categories