2009-11-09 1 views
8

Эй, у меня есть 2 таблицы в PostgreSql:PostgreSQL, выберите из 2 таблиц, но только последний элемент из таблицы 2

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 

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

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

ответ

7

Вы можете создать производную таблицу, которая содержит только самые последние «обновление» записи в 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) 
3

Из верхней части моей головы:

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

-1

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

SELECT * FROM documents, updates 
    WHERE documents.id=1 AND updates.document_id=1 
    AND updates.date = (SELECT MAX (date) From updates) 
+0

Нет, как написано в настоящее время, это не будет работать. Ваш подзапрос возвращает самую последнюю «дату» из всей таблицы обновлений независимо от документа, так что это приведет к результатам, только если выбранные вами документы, которые вы выбрали, были обновлены в самую последнюю дату обновления. – pilcrow

+0

Вы правы. Подзапрос должен читать SELECT MAX (дата) Из обновлений, где id = 1) –

2
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).

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

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; 
12

Использование 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 
Смежные вопросы