简体   繁体   中英

Get column values based on last entry (not null)

I have a table in MySQL which holds conversations. These conversation are composed of messages. A single conversation looks like the table below.

Importance and eId 's are only sometimes set. What I am trying to get from the table is the last message in the conversation ( messageId = 4) but with the last set importance and last set eId .

So, from this table

+----------------+-----------+----------+----------+------------+-------+---------+
| conversationId | messageId | time     | status   | importance | eId   | message |
+----------------+-----------+----------+----------+------------+-------+---------+
| 25             | 4         | 11:00:00 | feedback | NULL       | NULL  | d..     |
+----------------+-----------+----------+----------+------------+-------+---------+
| 25             | 3         | 10:00:00 | open     | MEDIUM     | NULL  | c..     |
+----------------+-----------+----------+----------+------------+-------+---------+
| 25             | 2         | 09:00:00 | feedback | NULL       | 123   | b...    |
+----------------+-----------+----------+----------+------------+-------+---------+
| 25             | 1         | 08:00:00 | open     | HIGH       | NULL  | a...    |
+----------------+-----------+----------+----------+------------+-------+---------+

I need to get this result

+----------------+-----------+----------+----------+------------+-------+---------+
| conversationId | messageId | time     | status   | importance | eId   | message |
+----------------+-----------+----------+----------+------------+-------+---------+
| 25             | 4         | 11:00:00 | feedback | MEDIUM     | 123   | d..     |
+----------------+-----------+----------+----------+------------+-------+---------+

I can't get the query to work. Any help would be appriciated. Thanks.

This one is not necessarily the best solution as I had to create this in my local SQL Server (SQL fiddle was down when tried and I have no MySQL installed), also a "quick and dirty" query (means: there might be a better solution for your problem), but as I am keen to help I post it anyway.
If you happen to wait for another, possibly better solution from the community, I will not feel offended :) That is what I wanted to say :)

SELECT TOP 1 conversationId,messageId,RecTime,ConvStatus,
       (
            SELECT TOP 1 importance
            FROM Conversations
            WHERE importance IS NOT NULL
            ORDER BY messageId DESC
       ) AS importance,
       (
            SELECT TOP 1 eId
            FROM Conversations
            WHERE eId IS NOT NULL
            ORDER BY messageId DESC
       ) AS eId,
UsrMessage
FROM Conversations
ORDER BY messageId DESC
GO

(do not forget that you might have to change "formatting items" to make it work in MySQL)

If there is more than one conversationId in the table, and you want to get the desired result for all of the conversationIds at the same time, then I think you need to join 3 subqueries within subqueries. Something like the 3 below:

SELECT messages.conversationId, messages.messageId, messages.time, messages.status, messages.message
FROM messages
JOIN  (
  SELECT conversationId, MAX(messageId) as messageId
  FROM messages
  GROUP BY conversationId) as m2
ON (messages.messageId = m2.messageId);


SELECT messages.conversationId, messages.importance
FROM messages
JOIN  (
  SELECT conversationId, MAX(messageId) as messageId
  FROM messages
  WHERE importance IS NOT NULL     
  GROUP BY conversationId) as m3
ON (messages.messageId = m3.messageId);

SELECT messages.conversationId, messages.eId
FROM messages
JOIN (
  SELECT conversationId, MAX(messageId) as messageId
  FROM messages
  WHERE eId IS NOT NULL
  GROUP BY conversationId) as m4
ON (messages.messageId = m4.messageId);

The JOIN would look like this:

SELECT 
main.conversationId, 
main.messageId, 
main.time, 
main.status, 
importance.importance, 
eId.eId, 
main.message
FROM (
  SELECT messages.conversationId, messages.messageId, messages.time, messages.status, messages.message
  FROM messages
  JOIN  (
    SELECT conversationId, MAX(messageId) AS messageId
    FROM messages
    GROUP BY conversationId) AS m2
    ON (messages.messageId = m2.messageId)
        ) AS main
JOIN (
  SELECT messages.conversationId, messages.importance
  FROM messages
  JOIN  (
    SELECT conversationId, MAX(messageId) AS messageId
    FROM messages
    WHERE importance IS NOT NULL
    GROUP BY conversationId) AS m3
    ON (messages.messageId = m3.messageId)
        ) AS importance
JOIN (
  SELECT messages.conversationId, messages.eId
  FROM messages
  JOIN (
    SELECT conversationId, MAX(messageId) AS messageId
    FROM messages
    WHERE eId IS NOT NULL
    GROUP BY conversationId) AS m4
    ON (messages.messageId = m4.messageId)
      ) AS eId
ON (
  main.conversationId = importance.conversationId
  AND main.conversationId = eId.conversationId
    );

Here's an sqlfiddle: http://sqlfiddle.com/#!2/857aa/38 . This assumes that messageId is unique. If it is not unique, then you need to join on messageId AND conversationId.

Maybe a bit oldschool but should do the trick :

SELECT c.conversationId as convId, max(c.messageId), t.time, s.status, i.importance, e.eId, c.message
  FROM convs c,
   (SELECT conversationId, max(time) AS time FROM convs) t,
   (SELECT conversationId, status FROM convs WHERE status IS NOT NULL ORDER BY messageId DESC) s,
   (SELECT conversationId, importance FROM convs WHERE importance IS NOT NULL ORDER BY messageId DESC) i,
   (SELECT conversationId, eId FROM convs WHERE eId IS NOT NULL ORDER BY messageId DESC) e
 WHERE 1=1
   AND t.conversationId = c.conversationId
   AND s.conversationId = c.conversationId
   AND i.conversationId = c.conversationId
   AND e.conversationId = c.conversationId
 GROUP BY c.conversationId

SQL Fiddle demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM