-1

I have some problem with my SQL query I have table message and table recipient

message is

ID    author    date
--------------------
0        1      2013-07-08 05:38:47
1        1      2013-07-13 05:38:47
2        1      2013-07-15 05:38:47
3        1      2013-07-15 05:38:47
4        2      2013-07-17 05:38:47
5        1      2013-07-28 05:38:47

recipient is

ID    m_id    recipient
--------------------
0        0      2
1        1      2
2        2      3
3        3      2
4        4      1
5        5      2

I need return rows from table message with group by recipient column from table recipient with last date in message table I'll try this

SELECT m.* 
FROM message as m
INNER JOIN recipient as r ON (m.ID = r.m_id)
WHERE m.author = 1
GROUP BY r.recipient
ORDER BY m.ID DESC

return is

ID    author    date
--------------------
2        1      2013-07-15 05:38:47
0        1      2013-07-08 05:38:47

but i need

ID    author    date
--------------------
5        1      2013-07-28 05:38:47
2        1      2013-07-15 05:38:47

please help

I USE MySQL Server 5.1


I found a solution to my problem

SELECT m.* 
FROM (
SELECT * FROM recipient 
    WHERE 1=1
    ORDER BY recipient.ID DESC
) AS r
INNER JOIN message AS m ON (r.m_id = m.ID)
WHERE m.author = 1
GROUP BY r.recipient

just reverse table recipient

Nikola Markovinović
  • 18,963
  • 5
  • 46
  • 51
Zachot
  • 3
  • 2

2 Answers2

2

Very simple and fast in PostgreSQL with DISTINCT ON - not standard SQL so not available in every RDBMS.

The question doesn't mention it, but deriving from the code examples it is actually looking for the row with the "last date" for each recipient for a given author.

SELECT DISTINCT ON (r.recipient)  m.*
FROM   message   m
JOIN   recipient r ON r.m_id = m.id
WHERE  m.author = 1
ORDER  BY r.recipient, m.date DESC, r.m_id -- to break ties

Details as well as multiple SQL standard alternatives here:
Select first row in each GROUP BY group?

Another solution with basic, standard SQL. Works with every major RDBMS, including MySQL (since that tag has been added):

SELECT m.* 
FROM   message   m
JOIN   recipient r ON r.m_id = m.id
WHERE  m.author = 1
AND NOT EXISTS (
   SELECT 1
   FROM   message   m1
   JOIN   recipient r1 ON r1.m_id = m1.id
   WHERE  r1.recipient = r.recipient 
   AND    m1.author = 1
   AND    m1.date > m.date
   )

Only the row with the latest date passes the NOT EXISTS anti-semi-join.

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
1

Presuming you're using SQL-Server, you can use a ranking function like ROW_NUMBER:

WITH CTE AS(
    SELECT m.*,
      RN=ROW_NUMBER()OVER(PARTITION BY r.recipient ORDER BY  m.date DESC)
    FROM message as m
    INNER JOIN recipient as r ON (m.ID = r.m_id)
    WHERE m.author = 1
)
SELECT * FROM CTE WHERE RN = 1

Demo

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939