HTCone
HTCone

Reputation: 13

SQL Aggregation AVG statement

Ok, so I have real difficulty with the following question.

Table 1: Schema for the bookworm database. Primary keys are underlined. There are some foreign key references to link the tables together; you can make use of these with natural joins.

For each publisher, show the publisher’s name and the average price per page of books published by the publisher. Average price per page here means the total price divided by the total number of pages for the set of books; it is not the average of (price/number of pages). Present the results sorted by average price per page in ascending order.

Author(aid, alastname, afirstname, acountry, aborn, adied).
Book(bid, btitle, pid, bdate, bpages, bprice).
City(cid, cname, cstate, ccountry).
Publisher(pid, pname).
Author_Book(aid, bid).
Publisher_City(pid, cid).

So far I have tried:

SELECT 
      pname,
      bpages, 
      AVG(bprice)
FROM book NATURAL JOIN publisher
GROUP BY AVG(bpages) ASC;

and receive

ERROR: syntax error at or near "asc" LINE 3: group by avg(bpages) asc;

Upvotes: 0

Views: 153

Answers (6)

kabijoy
kabijoy

Reputation: 303

Check this

     SELECT pname, AVG(bprice)
FROM book NATURAL JOIN publisher
GROUP by pname
ORDER BY AVG(bpages)

Upvotes: 0

cyan
cyan

Reputation: 747

The ASC is part of the ORDER BY clause. You are missing the ORDER BY here.

Reference: http://www.tutorialspoint.com/sql/sql-group-by.htm

Upvotes: 0

Randall
Randall

Reputation: 1521

You can't group by an aggregate, at least not like that. Also don't use natural join, it's bad habit to get into because most of the time you'll have to specify join conditions. It's one of those things you see in text books but almost never in real life.

OK with that out of the way, and this being homework so I don't want to just give you an answer without an explanation, aggregate functions (sum in this case) affect all values for a column within a group as limited by the where clause and join conditions, so unless your doing every row you have to specify what column contains the values you are grouping by. In this case our group is Publisher name, they want to know per publisher, what the price per page is. Lets work out a quick select statement for that:

select Pname as Publisher
  , Sum(bpages) as PublishersTotalPages
  , sum(bprice) as PublishersTotalPrice
  , sum(bprice)/Sum(bpages) as PublishersPricePerPage

Next up we have to determine where to get the information and how the tables relate to eachother, we will use books as the base (though due to the nature of left or right joins it's less important than you think). We know there is a foreign key relation between the column PID in the book table and the column PID in the Publisher table:

From Book B
  Join Publisher P on P.PID = B.PID

That's what is called an explicit join, we are explicitly stating equivalence between the two columns in the two tables (vs. implying equivalence if it's done in the where clause). This gives us a many to one relation ship, because each publisher has many books published. To see that just run the below:

select b.*, p.*
From Book B
  Join Publisher P on P.PID = B.PID

Now we get to the part that seems to have stumped you, how to get the many to one relationship between books and the publishers down to one row per publisher and perform an aggregation (sum in this case) on the page count per book and price per book. The aggregation portion was already done in our selection section, so now we just have to state what column the values our group will come from, since they want to know a per publisher aggregate we'll use the publisher name to group on:

Group by Pname
Order by PublishersPricePerPage Asc

There is a little gotcha in that last part, publisherpriceperpage is a column alias for the formula sum(bprice)/Sum(bpages). Because order by is done after all other parts of the query it's unique in that we can use a column alias no other part of a query allows that, without nesting the original query. so now that you have patiently waded through my explanation, here is the final product:

select Pname as Publisher
  , Sum(bpages) as PublishersTotalPages
  , sum(bprice) as PublishersTotalPrice
  , sum(bprice)/Sum(bpages) as PublishersPricePerPage
From Book B
  Join Publisher P on P.PID = B.PID
Group by Pname
Order by PublishersPricePerPage Asc

Good luck and hope the explanation helped you get the concept.

Upvotes: 1

Rigel1121
Rigel1121

Reputation: 2016

Base on what you're trying to achieve. You can try my query below. I used the stated formula in a CASE statement to catch the error when a bprice is divided by zero(0). Also I added ORDER BY clause in your query and there's no need for the AVG aggregates.

SELECT 
      pname,
      CASE WHEN SUM(bpages)=0 THEN '' ELSE SUM(bprice)/SUM(bpages) END price
FROM book NATURAL JOIN publisher
GROUP BY pname 
ORDER BY pname ASC;

Upvotes: 0

Vishal Suthar
Vishal Suthar

Reputation: 17193

You need Order By for sorting, which was missing:

SELECT 
      pname,
      bpages, 
      AVG(bprice)
FROM book NATURAL JOIN publisher
GROUP BY pname, bpages
order by AVG(bpages) ASC;

Upvotes: 0

SMA
SMA

Reputation: 37023

You need ORDER BY clause and not GROUP BY to sort record. So change your query to:

SELECT pname, AVG(bprice)
FROM book NATURAL JOIN publisher
GROUP by pname
ORDER BY AVG(bpages) ASC;

Upvotes: 1

Related Questions