Question

I want to print out only the max value. The problem is that I can't print that value it self. By using that max value, I need to determine which year should I print out. Everything works perfectly, what I need is to limit output only to one entry, by looking at taken maximum value. So I thought of this:

SELECT Years
FROM
(
    SELECT Book.Years,
        COUNT(Exempl.Taken) as taken
    FROM (Database.Exempl INNER JOIN Database.Book ON Exempl.Numb = Book.Numb)
    GROUP BY Book.Years
) as MyTable
WHERE (SELECT MAX(taken) FROM MyTable)

But I get an error. It doesn't understand MyTable. But I defined it as MyTable. What is the problem?

Was it helpful?

Solution

Your two immediate problems:

  • The derived table MyTable (alias name for the subquery) is not visible in another subquery one level below. LATERAL in Postgres 9.3 would allow something of the kind, but the query is backwards anyway.

  • The expression MAX(taken) does not evaluate to boolean, which would make it a valid WHERE clause but, again, the whole approach is incorrect.

Rewrite this. Probably the shortest form to get what (I think) you are after:

SELECT b.years, count(e.taken) AS ct_taken
FROM   database.book   b
JOIN   database.exempl e USING (numb)
GROUP  BY 1
ORDER  BY 2 DESC
LIMIT  1;
  1. Join table book to table exempl on the column numb. Since the columns have the same name, I simplified with USING. This is optional. Also using table aliases to simplify the syntax. Also optional.

  2. Group by book.years and count the number rows where exempl.taken is NOT NULL. If exempl.taken is defined NOT NULL you can simplify to count(*).

  3. Order the result by this count (ORDER BY 2) and only return one row (LIMIT 1) with the maximum count. If there are multiple rows with the same maximum, the pick is arbitrary unless you add more ORDER BY items.

Details in the manual about SELECT.

Do you really have a schema called database? That's a most confusing design. Consider fixing that.

If there are multiple years for the biggest count, you get an arbitrary pick from those unless you add more ORDER BY items.

Without LIMIT

Use row_number() as mentioned by a_horse, but over the count, not the base column:

SELECT years, ct_taken
FROM  (
   SELECT b.years, count(e.taken) AS ct_taken
          row_number() OVER (ORDER BY count(e.taken) DESC) AS rn
   FROM   database.book   b
   JOIN   database.exempl e USING (numb)
   GROUP  BY 1
   ORDER  BY 2 DESC
   ) sub
WHERE  rn = 1;

This works because you can have window functions over aggregate functions.

OTHER TIPS

SELECT Years
FROM
(
  SELECT Book.Years,
         row_number() over (partition by book.years order by Exempl.Taken desc) as rn
  FROM Database.Exempl 
    JOIN Database.Book ON Exempl.Numb = Book.Numb
) as MyTable
WHERE rn = 1;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top