开发者

Relational database query question

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 identical document_id.
  • revision_id is unique across all revisions for all documents.
  • contents is a blob of data that represents the document, and user_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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜