2010-05-07 17 views
5

Ho un ente JPA 2 denominato Chirurgia. Ha un membro chiamato trasfusioneUnità che è un Numero intero.La funzione di aggregazione avg JPQL funziona con Integers?

Ci sono due voci nel database. L'esecuzione di questa dichiarazione JPQL:

Select s.transfusionUnits from Surgery s 

produce il risultato atteso:

2 
3 

La seguente dichiarazione produce la risposta attesa di :

Select sum(s.transfusionUnits) from Surgery s 

mi aspetto la risposta dei seguenti dichiarazione per essere 2.5, ma restituisce 2.0 invece.

Select avg(s.transfusionUnits) from Surgery s 

Se eseguo l'istruzione su un membro (Float) diverso, il risultato è corretto. Qualche idea sul perché questo sta accadendo? Devo fare una sorta di cast in JPQL? È possibile? Sicuramente mi manca qualcosa di banale qui.

risposta

7

In primo luogo, mi permetta di riassumere quello che la specifica JPA 2.0 dice di AVG (vedere paragrafo 4.8.5 aggregazione nelle SELECT clausola per il contenuto completo)

La funzione AVG prende un percorso di campo Stato espressione come argomento e calcola il valore medio del campo di sate sul gruppo. Il campo dello stato deve essere numerico e il risultato è returnd come Double.

Così, dopo una prima lettura, mi aspettavo il seguente frammento di passare:

Query q = em.createQuery("select avg(s.transfusionUnits) from Surgery s"); 
Double actual = (Double) q.getSingleResult(); 
assertEquals(2.5d, actual.doubleValue()); 

ma non ha, mi è stato sempre 2.0 come risultato (un doppio, ma non il risultato atteso).

Quindi ho esaminato il livello di database e mi sono reso conto che la query SQL non stava effettivamente restituendo 2.5. E in effetti, questo è ciò che la documentazione del mio database dice su AVG:

Il valore medio (medio). Se nessuna riga è selezionata, il risultato è NULL. Gli aggregati sono consentiti solo in istruzioni selezionate. Il valore restituito è dello stesso tipo di dati del parametro.

Mi aspettavo troppo. JPA restituirà il risultato come un doppio, ma non farà alcuna magia. Se la query non restituisce un risultato con la precisione richiesta, non sarà possibile ottenerlo a livello di Java.

Quindi, senza cambiare il tipo di transfusionUnits, ho dovuto eseguire questa query nativo per ottenere le cose di lavoro:

Query q = em.createNativeQuery("SELECT AVG(CAST(s.transfusionUnits as double)) from Surgery s"); 
Double actual = (Double) q.getSingleResult(); 
assertEquals(2.5d, actual.doubleValue()); 

Aggiornamento: Sembra che alcuni di database (ad esempio MySQL) restituiscono un valore con una parte decimale quando si utilizza AVG su una colonna INT (che ha senso, indipendentemente dal comportamento documentato del database che ho usato qui). Per gli altri database, la versione precedente potrebbe essere gestita con nel "dialetto" (ad esempio vedere HHH-5173 per Hibernate) per evitare problemi di portabilità tra il database quando si utilizza JPQL.

1

Lanciare il campo medio per raddoppiare fa il trucco. Non sono sicuro delle implicazioni sulle prestazioni, ma non dovrebbe essere nulla di male:

+0

Non funziona per me, sto ricevendo l'errore che dovrebbe esserci) piuttosto che + segno. –

+0

ha funzionato per me con openjpa, sembra essere dipendente dal provider – MarianP

Problemi correlati