简体   繁体   中英

Using Distinct(col) in a SELECT with more than one column selected

my goal is to return a distinct list of 'mFrom' and only pull the latest 'date' from 'messages' table..

Table: messages
id     mFrom     mTo   date
--     -----     ---   ----
int    int       int   datetime

I am trying to use this query:

SELECT DISTINCT(mFrom), date FROM messages WHERE mTo = '116'

But am receiving these results:

mFrom   date
9     | 2016-11-17 00:30:03
11    | 2016-11-17 12:35:08
11    | 2016-11-17 12:35:35

and I would like to see these results instead..

mFrom  date
9     | 2016-11-17 00:30:03
11    | 2016-11-17 12:35:35

Any help is appreciated. Saw similar answers using GROUP BY and an inner SELECT but having trouble coming up with a comparable query for my specific fields..

GROUP BY seems right.

SELECT mFrom, MAX(date) as date 
FROM messages 
WHERE mTo = '116' 
GROUP BY mFrom

Let's say you have more columns that are unique in play, eg you want the latest message from mFrom but you also want mTo as well. Then you should consider a partitioned Row Number. For systems eg sql-server that support Windows Functions typically they will have a ROW_NUMBER() function that you can use. Here is an example using Common Table Expression [CTE] and ROW_NUMBER() . Note using RANK() or DENSE_RANK() instead will allow for ties.

;WITH cte AS (
    SELECT *
       ,ROW_NUMBER() OVER (PARTITION BY mFrom ORDER BY Date DESC) as RowNumber
    FROM
       Messages
    WHERE
       mTo = 116
)

SELECT *
FROM
    cte
WHERE
   RowNumber = 1

In my sql this becomes more complicated and you can do it via using variables:

SELECT *
FROM
    (
       SELECT
          m.*
          ,(@rn:= if(@mFrom = mFrom, @rn + 1, 
                if(@mFrom:=mFrom, 1, 1)
                )) as RowNumber
       FROM
          Messages m
          CROSS JOIN (SELECT @mFrom:=0, @rn:=0) var
       WHERE
          mTo = 116
    ) t
WHERE
    t.RowNumber = 1

Or in either system you can use the GROUP BY technique that Gareth Shows and relate it back to the original table, or IN or EXISTS all of these methods will return ties if 2 messages of mFrom share the same MAX(date). here is an example with a join.

SELECT *
FROM
    Messages m
    INNER JOIN (SELECT mFrom, MAX(date) as date
             FROM
                Messages
             WHERE
                mTo = 116
             GROUP BY
                mFrom) t
    ON m.mFrom = t.mFrom
    AND m.date = t.date
WHERE
    mTo = 116
11 | 2016-11-17 12:35:08
11 | 2016-11-17 12:35:35

you can see the date time field, time is off by couple of seconds.

You can do is,

SELECT DISTINCT(mFrom), cast(date as date) FROM messages WHERE mTo = '116'

This will remove the time and give you

mFrom date
9 | 2016-11-17 
11 | 2016-11-17 

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