问题
I need to execute a query for retrieving the item with the soonest expire date for each customer.
I have the following product table:
PRODUCT
|ID|NAME |EXPIRE_DATE|CUSTOMER_ID
1 |p1 |2013-12-31 |1
2 |p2 |2014-12-31 |1
3 |p3 |2013-11-30 |2
and I would like to obtain the following result:
|ID|EXPIRE_DATE|CUSTOMER_ID
1 |2013-12-31 |1
3 |2013-11-30 |2
With Mysql I would have a query like:
SELECT ID,min(EXPIRE_DATE),CUSTOMER_ID
FROM PRODUCT
GROUP BY CUSTOMER_ID
But I am using HyperSQL and I am not able to obtain this result.
With HSQLDB I get this error: java.sql.SQLSyntaxErrorException: expression not in aggregate or GROUP BY columns: PRODUCT.ID
.
If in HyperSQL I modify the last row of the query like GROUP BY CUSTOMER_ID,ID
I obtain the same entries of the original table.
How can I compute the product with the soonest expire date for each customer with HSQLDB??
回答1:
Assuming sub queries are supported, you can join the table on itself like such:
SELECT P.ID, P.EXPIRE_DATE, P.CUSTOMER_ID
FROM PRODUCT P
JOIN (
SELECT CUSTOMER_ID, MIN(EXPIRE_DATE) MIN_EXPIRE_DATE
FROM PRODUCT
GROUP BY CUSTOMER_ID
) P2 ON P.CUSTOMER_ID = P2.CUSTOMER_ID
AND P.EXPIRE_DATE = P2.MIN_EXPIRE_DATE
回答2:
In MySQL, you are getting an arbitrary id
for each customer. In most other dialects of SQL, you need to specify which you want. This will work:
SELECT min(ID), min(EXPIRE_DATE), CUSTOMER_ID
FROM PRODUCT
GROUP BY CUSTOMER_ID;
If you are trying to get the id
associated with the smallest expire date, then MySQL is not doing that. Here is one way to do this:
select p.*
from Product p join
(select customer_id, min(Expire_date) as min_ed
from Product p
group by customer_id
) psum
on p.customer_id = psum.customer_id and p.Expire_date = psum.min_ed
This is standard SQL and will run on any database (although some databases have functionality that is cleaner and more efficient).
回答3:
MySQL allows non ANSI group by which can often give wrong results. HSQL is acting correctly.
There are 2 options:
Remove ID
SELECT min(EXPIRE_DATE),CUSTOMER_ID
FROM PRODUCT
GROUP BY CUSTOMER_ID
Or, assuming that ID increases with EXPIRE_DATE
SELECT MIN(ID),min(EXPIRE_DATE),CUSTOMER_ID
FROM PRODUCT
GROUP BY CUSTOMER_ID
If you do need ID however, then you have to JOIN back
SELECT
P.ID, P.EXPIRE_DATE, P.CUSTOMER_ID
FROM
(
SELECT min(EXPIRE_DATE) AS minEXPIRE_DATE,CUSTOMER_ID
FROM PRODUCT
GROUP BY CUSTOMER_ID
) X
JOIN
PRODUCT P ON X.minEXPIRE_DATE = P.EXPIRE_DATE AND X.CUSTOMER_ID = P.CUSTOMER_ID
However, I think HSQL supports the ANY aggregate. This gives an arbitrary ID per MIN/GROUP BY.
SELECT ANY(ID),min(EXPIRE_DATE),CUSTOMER_ID
FROM PRODUCT
GROUP BY CUSTOMER_ID
来源:https://stackoverflow.com/questions/16733284/usage-of-group-by-and-min-with-hsqldb