Search code examples
javaoracle-databasejpagroup-byhour

Problem using JPA with Oracle and grouping by hour


I have a problem using JPA with Oracle and grouping by hour. Here's the scenario: I have an entiry named EventData. This entity has a java.util.Date field named startOfPeriod. This field maps in a table field of datatype DATE. The query I'm using is something like:

select min(ed.startOfPeriod) as eventDate,
(...)
from
Event e inner join e.eventDatas ed
(...)
group by
    year(ed.startOfPeriod), 
    month(ed.startOfPeriod), 
    day(ed.startOfPeriod), 
    hour(ed.startOfPeriod) 
order by 1

If I remove the group by "hour(ed.startOfPeriod)" it works fine (it doesn't produce any errors but it doesn'to do what I want). When I insert this group by clause it makes this exception:

Caused by: java.sql.SQLException: ORA-30076: campo de extração inválido para origem de extração
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:745)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:219)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:813)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1049)
at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:854)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1154)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3370)
at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3415)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:92)
at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208)
at org.hibernate.loader.Loader.getResultSet(Loader.java:1812)
at org.hibernate.loader.Loader.doQuery(Loader.java:697)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259)
at org.hibernate.loader.Loader.doList(Loader.java:2232)

Analysing the error code, it happens when "The extract source does not contain the specified extract field.". But the source of extraction (the startOfPeriod field) is of datatype DATE (which has an hour part).

The same code works like a charm in SQL Server.

Anyone knows what is going on?

Tnhks!


Solution

  • I didn't convert all my DATE fields to TIMESTAMP ones. Instead, I extended the Oracle's dialect to rewrite the hour function.

    Like that:

    public class Oracle9Dialect extends org.hibernate.dialect.Oracle9Dialect
    {
        public Oracle9Dialect()
        {
            super();
            registerFunction("hour", new SQLFunctionTemplate(Hibernate.INTEGER, "to_number(to_char(?1, 'hh24'))"));
        }
    }
    

    Using this dialect (org.hibernate.dialect.Dialect), the hour function will not use the ANSI hour function (extract(hour from <FIELD>)). It will use to_number(to_char(<FIELD>, 'hh24')) instead.

    The bad thing is that it always use the custom function (even when it doesn't need to be used, like with a TIMESTAMP field).

    This is what I did to solve my problem.