group by/having strange behaviour - php

i am facing a very weird problem.
Basically i need to extract a set of rows from a table where every row is the "oldest" in its own group.
The table is structured as follow:
id, integer
domain_id, integer
value, integer
created_at, datetime
My query is
SELECT * FROM domains_urls GROUP BY domain_id HAVING created_at = MAX(created_at)
If i am not wrong, it should group the rows by domain_id and extract the one that it matches created_at = MAX(created_at).
The point is that it does not work as expected!
The table content is
id domain_id value created_at
1 2 1 2014-05-25 10:30:13
2 1 3 2014-05-25 19:30:13
3 2 2 2014-05-25 11:30:13
4 2 7 2014-05-25 15:30:13
5 2 4 2014-05-25 12:30:13
6 2 5 2014-05-25 13:30:13
I should get two rows:
id domain_id value created_at
2 1 3 2014-05-25 19:30:13
4 2 7 2014-05-25 15:30:13
Instead i get only
id domain_id value created_at
4 2 7 2014-05-25 15:30:13
I'm using MySQL 5.5 on Windows 7
I need to use an HAVING+GROUP BY or a DISTINCT+ORDER BY (not tested).
Thanks!
EDIT:
Because i am a dumb (i should avoid working on sunday), the value returned by MAX is related to the table and not to the group!

You can accomplish this by joining the table back to itself using the max(created_at):
select du.*
from domains_urls du
join (select domain_id, max(created_at) maxcreated_at
from domains_urls
group by domain_id
) du2 on du.domain_id = du2.domain_id
and du.created_at = du2.maxcreated_at
SQL Fiddle Demo

Try something like this
Select * from urls as u group by u.id having u.created >= any (select created from urls u2 where u.id == u2.id)
i have not tested this, just wrote that from the top of my head

Related

How to select specific rows from MYSQL using PHP?

I have a chat app and I'm using PHP to get the data from MYSQL. I don't know how to word this the best way so I'm going to illustrate it the best way I can. Below is the an example the database setup.
DATABASE
ID MESSAGE DATETIME
------------------------------------------
1 Hello1. 2019-04-23 23:04:31
1 Hello2. 2019-03-23 10:04:31
1 Hello3. 2019-04-26 22:04:31
1 Hello4. 2019-04-23 13:01:10
2 Hello5. 2019-04-09 23:04:31
2 Hello6. 2019-04-23 23:04:31
2 Hello7. 2019-04-12 23:04:12
2 Hello8. 2019-04-11 20:04:31
3 Hello9. 2019-05-18 19:04:29
3 Hello10. 2019-02-22 23:04:31
3 Hello11. 2019-03-25 23:04:30
4 Hello12. 2019-04-23 15:04:31
4 Hello13. 2019-04-10 23:04:31
5 Hello14. 2019-01-14 23:04:31
SHOULD SELECT
ID MESSAGE DATETIME
------------------------------------------
1 Hello3. 2019-04-26 22:04:31
2 Hello6. 2019-04-23 23:04:31
3 Hello9. 2019-05-18 19:04:29
4 Hello12. 2019-04-23 15:04:31
5 Hello14. 2019-01-14 23:04:31
What I am trying to do is select the newest ID once for each different ID. So for ID 1 I would only be selecting the one with the newest DATETIME and so on and so forth.
mysql_query("SELECT * FROM messages WHERE ____?____ ORDER BY __?__");
So in this case there should only be 5 results. One of each id with the newest dateline. Any help would be greatly appreciated. Thanks.
You want the MAX(date) value, but one per ID. Because you also want the message, which does not appear in the GROUP BY clause, you should run a join on the table towards itself.
In the joined table, you get the maximum date and the ID, grouped by the ID - this gives you the highest date for each ID. Join that on your table on the ID and date, which allows you to get other columns that do not exist in the GROUP BY (as this GROUP BY is in the joined table, you don't need it in the main table).
SELECT m.id, m.message, m.date
FROM messages m
JOIN (
SELECT id, MAX(date) AS date
FROM foo
GROUP BY id
) AS t
ON m.id=t.id AND m.date=t.date
SQL fiddle shows the live result http://sqlfiddle.com/#!9/c70c3/7
You could try sorting them in a subquery before grouping by the ID as follows:
SELECT * FROM (SELECT * FROM messages ORDER BY DATETIME DESC) AS sortedMessages GROUP BY ID;
OR
mysql_query("SELECT * FROM (SELECT * FROM messages ORDER BY DATETIME DESC) AS sortedMessages GROUP BY ID;");
Or you could build a second table with conversations , that could have a subject and the latest message in the row , and then you would just return that full table, when opening the conversation you would pull the indivual messages from the messages table based on the conversationID

Select Distinct from new tol old in same table

I have one table named:
thread_comment
Now the table is getting filled as followed:
thread_comment_id thread_id user_id thread_comment thread_comment_time
1 2 1 This is a comment 2016-09-14 15:30:28
2 4 1 This is a comment 2016-09-14 15:32:28
3 2 1 This is a comment 2016-09-14 15:33:28
4 5 1 This is a comment 2016-09-14 15:34:28
5 7 1 This is a comment 2016-09-14 15:35:28
6 2 1 This is a comment 2016-09-14 15:37:28
7 2 1 This is a comment 2016-09-14 15:40:28
I want to show the newest threads to my page. for example:
as number one i want thread_comment_id 7
as number two i want thread_comment_id 5
I skipped 6 because i don't want any duplicates in the list.
In order to do so i did the folowing:
$sql = "SELECT DISTINCT thread_id FROM thread_comment ORDER BY thread_comment_time DESC"
This is kind of working (Not showing any duplicates). However the order does not make any sense...
For example:
It goes like 5 - 6 -4 - 7 etc...
The column used in the ORDER BY isn't specified in the DISTINCT. You need to use an aggregate function and GROUP BY to make the DISTINCT work.
SELECT DISTINCT thread_id, max(thread_comment_id) FROM thread_comment GROUP BY thread_id ORDER BY max(thread_comment_id) DESC, thread_id
EDIT: added aggregate func max()
Also thread_id is not mandatory in the ORDER BY
It I understand correctly, you want one row per thread. Here is a way to do this:
select tc.*
from thread_comment tc
where tc.thread_date = (select max(tc2.thread_date)
from thread_comment tc2
where tc2.thread_id = tc.thread_id
);

Mysql - finding duplicate values then only returning latest one then ignore it if it returns a certain result

I have
Tablename
id coid name test passfail testdate
VALUES
1 1 Chris mod1 fail 2015-05-20
2 1 Chris mod1 pass 2015-05-25
3 2 Patrick mod1 fail 2015-06-10
4 3 James mod1 2015-12-21
5 4 Agnes mod1 cancelled 2015-07-01
6 5 Freya mod1 pass 2015-07-01
7 5 Freya mod2 pass 2015-07-05
It lists who has done what test and when, and also if they passed or not.
I need to be able to return the results of the people who have not passed the the mod1 test.
if I use
SELECT *
FROM `tablename`
WHERE `test` = 'mod1' AND `passfail` != 'pass'
Chris is in the results because he has also failed the mod1, but i need to be able to ignore the fail because he has passed now.
The results I am after are...
3 2 Patrick mod1 fail 2015-06-10
4 3 James mod1 2015-12-21
5 4 Agnes mod1 cancelled 2015-07-01
The coid is the Contact ID just in case i get two people with the same name.
If I could find duplicate coid's that have done a mod1 then take the one latest date, and then check to see if it is a pass or not. I think that should give me the results i need, I have no idea how to do it though... please help
I have been trying all sorts of things on sqlfiddle
Try this...
SELECT *
FROM table_name
WHERE coid NOT IN (
SELECT coid
FROM same_table_name
WHERE test = 'mod1' AND passfail = 'pass'
);
Try out this:
select * from table_name t1
inner join (select max(id)as id from table_name group by coid) as t2
on t1.id=t2.id;
You can put any where conditions inside the subquery
I would think a GROUP BY would provide the data but I'm not sure as I don't have your data set
SELECT *
FROM `tablename`
WHERE `test` = 'mod1' AND `passfail` != 'pass'
GROUP BY coid
ORDER BY testdate DESC
In theory this should grab the latest coid

Sql query to show count(*) of groups while keeping all rows of the group

I have a table similar the following
id user_id father_id
1 1 1
2 2 1
3 3 2
4 4 2
5 5 2
6 6 3
7 7 4
I search for a sql query (prefer Fluent or Eloquent for Laravel 4) to give me the following result:
id user_id father_id family_members
3 3 2 3
4 4 2 3
5 5 2 3
1 1 1 2
2 2 1 2
6 6 3 1
7 7 4 1
As it can be observed family_members is the count of users who have the same father_id
select id, user_id, father_id, count(*) as family_members from users group by father_id
The query above, just keeps the top row of each group, but I want to keep all the other records and not only the first one; then sorting them first according to the family_members and then according to father_id
How can I achieve it?
I donĀ“t know Fluent, nor Eloquent, nor Laravel 4, but the sql query would be like this.
SELECT yourTable.*, auxTable.family_members
FROM yourTable
LEFT JOIN
(
SELECT father_id, COUNT(id) as family_members
FROM yourTable
GROUP BY father_id
)auxTable ON yourTable.father_id = auxTable.father_id
ORDER BY family_members DESC, yourTable.father_id ASC
I solved the problem by the following Fluent query based on the answer from segio0983
$users = DB::table('users')
->leftjoin(DB::raw('(SELECT father_id, COUNT(id) as family_members
FROM users
GROUP BY father_id) auxTable '),function($join)
{
$join->on('users.father_id', '=', 'auxTable.father_id');
})
->orderBy('auxTable.family_members','desc')
->orderBy('users.father_id','asc')
->select('users.id','users.father_id','auxTable.family_members');

MySql : Order by and Group By combining not giving the latest record

Using the following query I am looking for a solution to get the latest record that having some conditions.
But it gives me the first record, not the latest. I think its only considering the group by
Please advise me
SELECT * FROM `contacts` WHERE `id_receiver`=1 GROUP BY `id_thread` ORDER BY created DESC
id id_sender id_thread sender_email id_receiver created(datetime)
1 2 2 51 1 2012-03-24 13:44:48
2 4 4 1 5 2012-04-26 13:46:05
3 2 2 51 1 2012-04-09 12:12:30
Required output
id id_sender id_thread sender_email id_receiver created(datetime)
3 2 2 51 1 2012-04-09 12:12:30
I had done a test just swap the order by and group by , giving me an erros.
Anybody can just look in to this?. Thanks.
EDIT Edited question, forget to write id_thread
How can you GROUP BY id_thread when there is no id_thread column in your table?
SELECT *
FROM contacts
WHERE id_receiver = 1
--- GROUP BY id_thread
--- removed
ORDER BY created DESC
LIMIT 1 --- only show one row
Based on your comments, what you want is the latest (ordered by created) row for every id_thread, which is a different and more complex query. There's even a tag for this kind of queries, named [greatest-n-per-group].
SELECT c.*
FROM contacts AS c
JOIN
( SELECT id_thread, MAX(created) AS created
FROM contacts
WHERE id_receiver = 1
GROUP BY id_thread
) AS g
ON (g.id_thread, g.created) = (c.id_thread, c.created)
WHERE c.id_receiver = 1
if records goes sequential than you might SORT by id too -- if and only if it's created in sequential order --

Categories