I have a question about a particular query I'd like to execute against a PostgreSQL table. Although I welcome criticism of the 开发者_运维问答table scheme I've used I'm going to be more appreciative of answers to my actual question!
I'm using the uuid-ossp postgresql-contrib module and have the following table structure:
Column | Type | Modifiers | Storage | Description
---------------------+-----------------------------+-----------+----------+-------------
revision_id | uuid | not null | plain |
document_id | uuid | not null | plain |
user_id | uuid | not null | plain |
datetime_edited | timestamp without time zone | not null | plain |
contents | text | not null | extended |
Indexes:
"document_pkey" PRIMARY KEY, btree (revision_id)
The idea is that:
- A document may have one or more revisions. Revisions are not deleted. In order to update a document a new row is inserted with a new
revision_id
but an identicaldocument_id
. revision_id
is unique across all revisions for all documents.contents
is a blob of data that represents the document, anduser_id
identifies who updated the document.
I'm struggling to come up with a query that returns all the latest revisions for all documents created by a particular user. I know I can do, for example:
select * from document where user_id = '6a2aabc417b34ef99b14b10eaa8e9313';
but this returns all the documents. How do I drill down and ask for a grouping by document_id
, and also LIMIT 1
and return the newest revision_id
based on datetime_edited
?
EDIT: Since a document can have one or more revisions I've been far to vague in saying "all documents created by a user". By created I mean that the user has contributed one or more revisions to the documents, i.e. there is at least one revision where the user edited the document.
Is something like this even achievable in one query, or do I need to hit the database several times to achieve this?
EDIT: revision_id is not monotonically increasing. It's a random UUID. Hence, max(revision_id) != max(datetime_edited).
Select ...
From document As D
Join (
Select D1.document_id, Max( datetime_edited ) As datetime_edited
From document As D1
Group By D1.document_id
) As LastRevision
On LastRevision.document_id = D.document_id
And LastRevision.datetime_edited = D.datetime_edited
Where Exists (
Select 1
From document As D2
Where D2.document_id = D.document_id
And D2.user_id = '6a2aabc417b34ef99b14b10eaa8e9313'
)
An alternate form:
Select ...
From document As D
Join (
Select D1.document_id, Max( datetime_edited ) As datetime_edited
From document As D1
Group By D1.document_id
) As LastRevision
On LastRevision.document_id = D.document_id
And LastRevision.datetime_edited = D.datetime_edited
Join (
Select D2.document_id
From document As D2
Where D2.user_id = '6a2aabc417b34ef99b14b10eaa8e9313'
Group By D2.document_id
) As UserDocs
On UserDocs.document_id = D.document_id
Get the highest revision id for each document, then select those documents:
select *
from document
where revision_id in (
select max(revision_id)
from document
where user_id = '6a2aabc417b34ef99b14b10eaa8e9313'
group by document_id
)
Update:
As the version id is not incremental, you will have to select the document_id and it's latest datetime_edited, and join against the document table:
select d.*
from document d
inner join (
select document_id, max(datetime_edited) as datetime_edited
from document
where user_id = '6a2aabc417b34ef99b14b10eaa8e9313'
group by document_id
) x on x.document_id = d.document_id and x.datetime_edited = d.datetime_edited
精彩评论