PostgreSQL, выберите из 2 таблиц, но только самый последний элемент из таблицы 2 - PullRequest
11 голосов
/ 09 ноября 2009

Эй, у меня есть 2 таблицы в PostgreSql:

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

и некоторые данные:

документы:

| 1 | Test Title |

обновления:

| 1 | 1 | 2006-01-01 |
| 2 | 1 | 2007-01-01 |
| 3 | 1 | 2008-01-01 |

Итак, все обновления указывают на один и тот же документ, но все с разными датами обновления.

Что я пытаюсь сделать, это сделать выбор из таблицы документов, но также включить последнее обновление на основе даты.

Как должен выглядеть такой запрос? Это то, что у меня есть на данный момент, но я перечисляю все обновления, а не последнее, которое мне нужно:

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

включить; Причина, по которой мне это нужно в запросе, заключается в том, что я хочу сделать заказ по дате из шаблона обновлений!

Редактировать: этот скрипт сильно упрощенный, поэтому я должен быть в состоянии создать запрос, который возвращает любое число результатов, но включая последние обновленная дата. Я думал об использовании внутреннее соединение или левое соединение или что-то вот так!?

Ответы [ 5 ]

19 голосов
/ 10 ноября 2009

Использование PostgreSQL расширение DISTINCT ON:

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

Это займет первую строку из каждого кластера document.id в порядке ORDER BY.

Тестовый скрипт для проверки:

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
8 голосов
/ 09 ноября 2009

Вы можете создать производную таблицу, которая содержит только самые последние записи "обновлений" для каждого document_id, а затем присоединить "документы" к этому:

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;

Это будет обрабатывать «не обновленные» документы, например:

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)
4 голосов
/ 10 ноября 2009
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=?;

Имеет некоторые преимущества перед предыдущими ответами:

  • вы можете написать document_id только в одном удобном месте;
  • вы можете опустить, где, и вы получите таблицу всех документов и их последних обновлений;
  • Вы можете использовать более широкие критерии выбора, например, where documents.id in (1,2,3).

Вы также можете избежать подвыбора, используя group by, но вам придется перечислить все поля документов в group by:

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;
2 голосов
/ 09 ноября 2009

С макушки моей головы:

ORDER BY date DESC LIMIT 1

Если вы действительно хотите только идентификатор 1, вы можете использовать этот запрос:

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 голосов
/ 09 ноября 2009

Это также должно работать

SELECT * FROM documents, updates 
    WHERE documents.id=1 AND updates.document_id=1
    AND updates.date = (SELECT MAX (date) From updates) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...