简体   繁体   中英

Usage of GROUP BY and MIN with HSQLDB


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??

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

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).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM