Reputation: 19248
This has frustrated me a bit, and I have googled around for a while.
id int(11)
target_id int(11)
text text latin1_swedish_ci
ip_address varchar(20) latin1_swedish_ci
created_by_user_id int(11)
created_date datetime
Data example:
id target_id ip_address created_by_user_id text created_date
1 113 192.168.0.1 1 test1 2014-08-24 12:32:01
1 113 192.168.0.1 1 test2 2014-08-24 13:32:01
1 1 192.168.0.1 113 test3 2014-08-21 13:32:01
1 1 192.168.0.1 113 test4 2014-08-22 13:32:01
How could I select the latest result, and also group by target_id? I have tried the following SQL statement to group correctly, but it didn't bring the latest result.
SELECT
*
FROM
`fq_message`
GROUP BY
target_id
ORDER BY
id DESC
returns:
1 113 192.168.0.1 1 test1 2014-08-24 12:32:01
1 1 192.168.0.1 113 test3 2014-08-21 13:32:01
I want to achieve
1 113 192.168.0.1 1 test2 2014-08-24 13:32:01
1 1 192.168.0.1 113 test4 2014-08-22 13:32:01
Upvotes: 1
Views: 149
Reputation: 1709
Try his code:
SELECT
ID,
target_id,
ID_ADDRESS,
CREATED_BY_USER_ID,
(SELECT TEXT FROM [YOUR_TABLE_NAME] WHERE ID = TMP.ID AND TARGET_ID = TMP.TARGET_ID AND ID_ADDRESS = TMP.ID_ADDRESS AND CREATED_BY_USER_ID = TMP.CREATED_BY_USER_ID AND CREATED_DATE = TMP.CREATED_DATE),
CREATED_DATE
FROM
(
SELECT
ID,
target_id,
ID_ADDRESS,
CREATED_BY_USER_ID,
MAX(CREATED_DATE) AS CREATED_DATE
FROM
/* Instead of this from, use from [your table] */
(
SELECT 1 ID, 113 TARGET_ID, '192.168.0.1' ID_ADDRESS, 1 CREATED_BY_USER_ID, 'test1' TEXT, TO_DATE('2014-08-24 12:32:01', 'YYYY-MM-DD HH24:MI:SS') CREATED_DATE FROM DUAL UNION
SELECT 1 , 113 , '192.168.0.1' , 1 , 'test2' , TO_DATE('2014-08-24 13:32:01', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL UNION
SELECT 1 , 1 , '192.168.0.1' , 113 , 'test3' , TO_DATE('2014-08-21 13:32:01', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL UNION
SELECT 1 , 1 , '192.168.0.1' , 113 , 'test4' , TO_DATE('2014-08-22 13:32:01', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL
)
GROUP BY ID, target_id, ID_ADDRESS, CREATED_BY_USER_ID
) TMP
ORDER BY ID, CREATED_DATE DESC
Result:
1 113 192.168.0.1 1 8/24/2014 1:32:01 PM
1 1 192.168.0.1 113 8/22/2014 1:32:01 PM
Tested in Oracle
Upvotes: 0
Reputation: 238048
MySQL allows you to write queries that are formally not SQL. For example, the following query might work in MySQL, or it might not. A sane database would certainly reject it:
select *
from (
select *
from fq_message
order by
created_date desc
) SubQueryAlias
group by
target_id
This tells MySQL to sort before group, as you ask. But it's not real SQL. The SQL standard says subquery sets, and tables, are unordered. All other databases will reject the inner query as imposing a sort order that does not matter.
The query also selects *
but groups on target_id
. MySQL will grab the first value it encounters, which if it honors the subquery sort, is the latest value per target. But there is no guarantee that it will do so. How MySQL handles these things can even change per MySQL version.
A better approach is to write SQL that requires MySQL to do the right thing. One such way is a filtering join with the set of latest dates per target:
select msg.*
from fq_message msg
join (
select target_id
, max(created_date) as max_date_for_this_target
from fq_message
group by
target_id
) filter
on msg.target_id = filter.target_id
and msg.created_date = filter.max_date_for_this_target
The join
is an inner join
and will only return rows for which the on
clause finds a match. The effect is that messages that do not have the latest date for their target are filtered out.
See the greatest-n-per-group tag for more approaches and examples.
Upvotes: 3