views:

58

answers:

3

Hi, 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!

A: 

Not quite an answer, but it sounds suspiciously like a driver issue to me (especially as this works fine on SQLServer). What version of the Oracle driver are you using? Have you tried different versions?

karianna
Hmm, would've have preferred to leave that as a comment, but I don't have the rep, ah well!
karianna
It does seam to be an issue with my oracle install. If I run the select: "select extract(hour from startofperiod) from lum_moneventdata", it produces the same error. Should this work? I'm using the 10.2.0.4.0 ojdbc driver. Running over the Oracle 11g.
Berne
Not sure, but there are more modern drivers for 11g, see http://www.oracle.com/technetwork/database/features/jdbc/index-091264.html for details. Incidentally on Sybase (15) you'd need to use a time or datetime data type, the oracle docs do seem to conflict on this (saying DATE stores hour but then stating that to extract it you need to use timestamp). That's about the extent of my knowledge I'm afraid
karianna
I think my solution will be changing my field from DATE to TIMESTAMP (although it makes no sense for me).
Berne
Sounds reasonable, let us know how you get on!
karianna
+1  A: 

Have you tried TO_CHAR(d, 'HH24') instead? You could also trunc() to hours...

Samuel
The problem is that the JPA implementation (Hibernate) creates the query. Another problem is that this project must not be BD specific.
Berne
Just an update, select to_char(startofperiod, 'hh24') from lum_moneventdata this works perfectly but select extract(hour from startofperiod) from lum_moneventdata doesn't work at all (and it's exactly what the JPA impl does).
Berne
A: 

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.

Berne
A teammate of mine opened a bug in Hibernate's Jira. It is: http://opensource.atlassian.com/projects/hibernate/browse/HHH-5626
Berne