Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL "GROUP BY" issue

I'm designing a shopping cart. To circumvent the problem of old invoices showing inaccurate pricing after a product's price gets changed, I moved the price field from the Product table into a ProductPrice table that consists of 3 fields, pid, date and price. pid and date form the primary key for the table. Here's an example of what the table looks like:

pid    date     price
1      1/1/09   50
1      2/1/09   55
1      3/1/09   54

Using SELECT and GROUP BY to find the latest price of each product, I came up with:

SELECT pid, price, max(date) FROM ProductPrice GROUP BY pid

The date and pid returned were accurate. I received exactly 1 entry for every unique pid and the date that accompanied it was the latest date for that pid. However, what came as a surprise was the price returned. It returned the price of the first row matching the pid, which in this case was 50.

After reworking my statement, I came up with this:

SELECT pp.pid, pp.price, pp.date FROM ProductPrice AS pp
INNER JOIN (
    SELECT pid AS lastPid, max(date) AS lastDate FROM ProductPrice GROUP BY pid
) AS m
ON pp.pid = lastPid AND pp.date = lastDate

While the reworked statement now yields the correct price(54), it seems incredible that such a simple sounding query would require an inner join to execute. My question is, is my second statement the easiest way to accomplish what I need to do? Or am I missing something here? Thanks in advance!

James

like image 976
James Fu Avatar asked Nov 19 '09 09:11

James Fu


People also ask

Why we Cannot use WHERE with GROUP BY?

2. Confusing WHERE and HAVING. GROUP BY meal_category ; This statement will return an error because you cannot use aggregate functions in a WHERE clause.

Does GROUP BY Make query slower?

Improving performance with SQL aggregate functions The main problem with GROUP BY is that queries involving it are usually slow, especially when compared with WHERE -only queries.

Can you GROUP BY in SQL?

Group by is one of the most frequently used SQL clauses. It allows you to collapse a field into its distinct values. This clause is most often used with aggregations to show one value per grouped field or combination of fields. We can use an SQL group by and aggregates to collect multiple types of information.

Can we use GROUP BY in case statement?

The case statement in SQL returns a value on a specified condition. We can use a Case statement in select queries along with Where, Order By, and Group By clause. It can be used in the Insert statement as well.


1 Answers

The reason you get an arbitrary price is that mysql cannot know which columns to select if you GROUP BY something. It knows it needs a price and a date per pid and can fetch the latest date as you requested with max(date) but chooses to return a price that is most efficient for him to retrieve - you didn't provide an aggregate function for that column (your first query is not valid SQL, actually.)

Your second query looks OK, but here is a shorter alternative:

SELECT pid, price, date
FROM ProductPrice p
WHERE date = (SELECT MAX(date) FROM ProductPrice tmp WHERE tmp.pid = p.pid)

But if you access the latest price a lot (which I think you do), I would recommend adding the old column back to your original table to hold the newest value, if you have the option of altering the database structure again.

like image 102
soulmerge Avatar answered Sep 28 '22 09:09

soulmerge