PostgreSQL , Select from 2 tables, but only the latest element from table 2

后端 未结 5 2069
星月不相逢
星月不相逢 2021-02-07 07:07

Hey, I have 2 tables in PostgreSql:

1 - documents: id, title
2 - updates: id, document_id, date

and some data:

documents:

相关标签:
5条回答
  • 2021-02-07 07:26
    select *
    from documents
    left join updates
      on updates.document_id=documents.id
      and updates.date=(select max(date) from updates where document_id=documents.id)
    where documents.id=?;
    

    It has the some advantages over previous answers:

    • you can write document_id only in one place which is convenient;
    • you can omit where and you'll get a table of all documents and their latest updates;
    • you can use more broad selection criteria, for example where documents.id in (1,2,3).

    You can also avoid a subselect using group by, but you'll have to list all fields of documents in group by clause:

    select documents.*, max(date) as max_date
      from documents
      left join updates on documents.id=document_id
      where documents.id=1
      group by documents.id, title;
    
    0 讨论(0)
  • 2021-02-07 07:35

    This should also work

    SELECT * FROM documents, updates 
        WHERE documents.id=1 AND updates.document_id=1
        AND updates.date = (SELECT MAX (date) From updates) 
    
    0 讨论(0)
  • 2021-02-07 07:44

    You may create a derived table which contains only the most recent "updates" records per document_id, and then join "documents" against that:

    SELECT d.id, d.title, u.update_id, u."date"
    FROM documents d
    LEFT JOIN
    -- JOIN "documents" against the most recent update per document_id
    (
    SELECT recent.document_id, id AS update_id, recent."date"
    FROM updates
    INNER JOIN
    (SELECT document_id, MAX("date") AS "date" FROM updates GROUP BY 1) recent
    ON updates.document_id = recent.document_id
    WHERE
      updates."date" = recent."date"
    ) u
    ON d.id = u.document_id;
    

    This will handle "un-updated" documents, like so:

    pg=> select * from documents;
     id | title 
    ----+-------
      1 | foo
      2 | bar
      3 | baz
    (3 rows)
    
    pg=> select * from updates;
     id | document_id |    date    
    ----+-------------+------------
      1 |           1 | 2009-10-30
      2 |           1 | 2009-11-04
      3 |           1 | 2009-11-07
      4 |           2 | 2009-11-09
    (4 rows)
    
    pg=> SELECT d.id ...
     id | title | update_id |    date    
    ----+-------+-----------+------------
      1 | foo   |         3 | 2009-11-07
      2 | bar   |         4 | 2009-11-09
      3 | baz   |           | 
    (3 rows)
    
    0 讨论(0)
  • 2021-02-07 07:45

    From the top of my head:

    ORDER BY date DESC LIMIT 1
    

    If you really want only id 1 your can use this query:

    SELECT * FROM documents,updates 
        WHERE documents.id=1 AND updates.document_id=1 
        ORDER BY date DESC LIMIT 1
    

    http://www.postgresql.org/docs/8.4/interactive/queries-limit.html

    0 讨论(0)
  • 2021-02-07 07:47

    Use PostgreSQL extension DISTINCT ON:

    SELECT  DISTINCT ON (documents.id) *
    FROM    document
    JOIN    updates
    ON      updates.document_id = document_id
    ORDER BY
            documents.id, updates.date DESC
    

    This will take the first row from each document.id cluster in ORDER BY order.

    Test script to check:

    SELECT  DISTINCT ON (documents.id) *
    FROM    (
            VALUES
            (1, 'Test Title'),
            (2, 'Test Title 2')
            ) documents (id, title)
    JOIN    (
            VALUES
            (1, 1, '2006-01-01'::DATE),
            (2, 1, '2007-01-01'::DATE),
            (3, 1, '2008-01-01'::DATE),
            (4, 2, '2009-01-01'::DATE),
            (5, 2, '2010-01-01'::DATE)
            ) updates (id, document_id, date)
    ON      updates.document_id = documents.id
    ORDER BY
            documents.id, updates.date DESC
    
    0 讨论(0)
提交回复
热议问题