2017-02-16 7 views
1

Я хотел бы создать sql-запрос, который возвращает некоторые данные строк, которые имеют максимальное значение в некоторой группе. Рассмотрим следующий пример демонстрации:Postgresql - Получение строки с максимальным значением в столбце

Существует три таблицы: страна, издатель и книга. Каждый издатель принадлежит одной стране, и каждая книга имеет одного издателя. Определения может выглядеть

Country(country_id, country_name) 
Publisher(pub_id, pub_name, fk_pub_country) 
Book(book_id, book_name, release_date, fk_book_publisher) 

Я хотел бы, чтобы выбрать (COUNTRY_ID, BOOK_NAME), сгруппированные по стране, так что каждая строка содержит имя наиболее недавно выпущенной книги в этой стране. Если в тот же день выпущено несколько книг, я должен получить тот, у которого самый высокий идентификатор.

Если я просто использую группу by -clause и max, я не могу включить название книги. Если я выберу view (country_id, max_date) и присоединяюсь к нему издателем и книгой, я могу получить несколько строк для каждой страны. Как я могу достичь желаемого результата?

+0

Домашнее задание? Добавьте пример данных таблицы и ожидаемый результат, как форматированный текст. Также покажите нам свою текущую попытку запроса - и опишите, что происходит не так. – jarlh

ответ

2
SELECT DISTINCT ON (country_id) 
    country_id, 
    book_name 
FROM country 
JOIN publisher ON fk_pub_country = country_id 
JOIN book ON fk_book_publisher = pub_id 
ORDER BY 
    country_id, 
    release_date DESC, 
    book_id DESC 
+0

Спасибо! Это также кажется хорошим решением, учитывая производительность. – eko

0

Вы можете использовать подзапрос:

select c.country_id, 
     (select b.book_name 
     from Book b 
      join Publisher p on p.pub_id = b.fk_book_publisher 
     where p.fk_pub_country = c.country_id 
     order by b.release_date desc, b.book_id desc limit 1) as book_name 
from Country c 
0

Вы говорите:

Если я просто использовать группу по -clause и макс, я не могу включить книгу имя.

Но вы не можете позволить боссу Postgres так вокруг. Просто возьмите первый из п отсортированных записей из массива результатов, как так (непроверенные):

SELECT 
    country_id, 
    (array_agg(book_name))[1] as book_name 
FROM country 
JOIN publisher ON fk_pub_country = country_id 
JOIN book ON fk_book_publisher = pub_id 
GROUP BY country_id ORDER BY release_date DESC; 

Поскольку они заказали, как вы хотите, (array_agg(...))[1] захватывает первый элемент из списка и, эй, вы получил тушеное мясо.