3

I'd like to form an sql query, which returns some data of rows, which have max value in some group. Consider the following example for a demonstration:

There are three tables: country, publisher and book. Each publisher belongs to one country and each book has one publisher. Definitions could look like

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

I'd like to select (country_id, book_name) grouped by country, so that each row contains the name of the most recently released book in that country. If there are multiple books released on the same day, I should get the one with the highest id.

If I just use group by -clause and max, I cannot include the book name. If I select view (country_id, max_date) and join it with publisher and book, I may receive multiple rows per country. How could I achieve the desired result?

1
  • Homework? Add sample table data and the expected result, both as well formatted text. Also show us your current query attempt - and describe what's going wrong. Commented Feb 16, 2017 at 10:51

3 Answers 3

8
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
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! This also seems to be a good solution considering performance.
1

You could use a subquery:

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

Comments

1

You say:

If I just use group by -clause and max, I cannot include the book name.

But you can't let Postgres boss you around like that. Just grab the first of n sorted records from an array of results like so (untested):

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;

Since they're ordered how you want, (array_agg(...))[1] grabs the first item from the list and, hey, you got a stew goin'.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.