0

I have a system that stores documents in a database, each user can create multiple documents and each document is saved in different versions. Each user has a unique token. Each document has a unique id. Each document is being stored many times but at different times.

Example of my table:

|AI  |token |docid   time|
|1   |id1   |doc1    1000|
|2   |id2   |doc2    1001|
|3   |id1   |doc1    909 |
|4   |id2   |doc1    1020|
|5   |id1   |doc3    801 |

What I need is a query that gives me only the newest of each document for a particular user.

So in this example I would like for user with token id1:

1   id1   doc1    1000
5   id1   doc3    801

How would a query that achieve this look like?

u32i64
  • 2,384
  • 3
  • 22
  • 36

1 Answers1

1

With this query:

select token, docid, max(time) time
from tablename
group by token, docid

you get the newest time for each token and docid.
If you don't need the AI column then you're done.
If you also need the AI column you must join this query to the table:

select t.* 
from tablename t inner join (
  select token, docid, max(time) time
  from tablename
  group by token, docid
) g on g.token = t.token and g.docid = t.docid and g.time = t.time

If you want results only for token = 'id1', you can add a condition:

where t.token = 'id1'

or you can also use NOT EXISTS:

select t.* 
from tablename t
where 
  t.token = 'id1'
  and not exists (
    select 1 from tablename
    where token = t.token and docid = t.docid and time > t.time
  );

See the demo.
Results:

| ai  | token | docid | time |
| --- | ----- | ----- | ---- |
| 1   | id1   | doc1  | 1000 |
| 5   | id1   | doc3  | 801  |
forpas
  • 160,666
  • 10
  • 38
  • 76
  • 1
    Don't forget filtering on user `token`. – Uueerdo May 07 '19 at 20:58
  • @Uueerdo thanks. I completely missed that part. – forpas May 07 '19 at 21:08
  • Sorry man - i'm getting the correct rows, BUT and this i completely realize i should have added to my question is that i also need more row data. I have another column called filename and i also need that. It shouldn't sort or do anything with the filename column i just need it to be part of the result. I thought (due to my inexperience with sql that i could add that column name at the end of the list) -> but then it messes up the results. Could i ask you, how the command should be if i also want that column to be part of the result? – Sami Al-beik May 08 '19 at 17:13
  • Also i'm really not experienced in sql at all -> all these command that contain stuff like "t.*" or t.docid , don't return anything on my system. I'm on mySql 4.6.1, maybe that has anything to do with it. It's the version that came with my web service so i can't upgrade. – Sami Al-beik May 08 '19 at 17:14
  • With `t.*` you get **all the columns** of the table aliased as `t`. In this case `t` is your table's name. I don't understand why you don't get all the columns. I can only test the code in MYSql 5.7+. – forpas May 08 '19 at 17:17
  • @forpas ok, once again my inexperience was at fault - all works :D getting the entre row data. Thanks for your time and help :D – Sami Al-beik May 08 '19 at 17:31
  • Fine if it works. – forpas May 08 '19 at 17:32