How to execute raw query in JPA? - postgresql

I'm trying to execute a raw query like this:
em.createNativeQuery(
"WITH RECURSIVE recursetree(id, parent_id) AS (\n" +
"SELECT id, parent_g_id FROM group WHERE parent_g_id = 2\n" +
"UNION\n" +
" SELECT t.id, t.parent_g_id\n" +
" FROM group t\n" +
" JOIN recursetree rt ON rt.id = t.parent_g_id\n" +
" )\n" +
"SELECT * FROM recursetree;").getResultList();
On the Postgres side (via PGAdmin) it works fine, but from Java it get the following error:
java.lang.IllegalArgumentException: argument type mismatch
What do I do wrong? How to execute a really raw query on Postgres from a Java EE environment?

Related

Syntax error when querying results directly to a DTO

My native query -
interface PodcastRepository: JpaRepository<Podcast, Long> {
#Query(value = "SELECT new com.krtkush.sample.modules.podcast.models.PodcastDTO" +
"(p.id, p.author, p.title, p.description c.name, c2.name) " +
"AS sub_category_name FROM podcasts p " +
"LEFT JOIN categories c ON p.podcast_category_id = c.category_id " +
"LEFT JOIN categories c2 ON p.podcast_subcategory_id = c2.category_id " +
"WHERE p.podcast_owner = :ownerId", nativeQuery = true)
fun getPodcastsByOwner(#Param("ownerId")owner: Long): List<PodcastDTO>
}
However, when I execute the function I get the following error -
org.postgresql.util.PSQLException: ERROR: syntax error at or near "." Position: 15
position 15 is . after SELECT new com
I'm following this tutorial - https://smarterco.de/spring-data-jpa-query-result-to-dto/
The difference is that I'm using SQL rather than JPQL.

Transforming complex postgres query into JPQL for Spring Hibernate repository

I have the following Postgres SQL query, in order to get alerts with the latest date:
SELECT latest_alerts.subject_id,
latest_alerts.alertconfiguration_id_id,
latest_alerts.alert_level,
latest_alerts.maxdate
FROM (SELECT subject_id,
alertconfiguration_id_id,
alert_level,
Max(date) AS maxdate
FROM alert
WHERE subject_id IN ( 'da157532-8de5-4c0c-8608-d924e670d5db', '63b99886-77c8-4784-b8f0-7ff5310f1272' )
AND alertconfiguration_id_id IN (
'6feb6b8b-6b96-4d5d-ac58-713b3cd637a0'
)
GROUP BY subject_id,
alertconfiguration_id_id,
alert_level) AS latest_alerts
INNER JOIN alert
ON alert.date = latest_alerts.maxdate
AND alert.subject_id = latest_alerts.subject_id
AND alert.alertconfiguration_id_id =
latest_alerts.alertconfiguration_id_id
AND alert.alert_level IN ( 'WARNING' )
ORDER BY latest_alerts.maxdate DESC;
This runs well on the postgres database generated by Hibernate. Note the odd id_id construction is because of an embedded key.
But I'm struggling to transform this into a JPA/JPQL query that I can use in a Spring Boot application. So far I have this:
#Query("SELECT" +
" latest_alerts.subject," +
" latest_alerts.alertConfiguration," +
" latest_alerts.alertLevel," +
" latest_alerts.max_date" +
"FROM" +
" (SELECT" +
" subject," +
" alertConfiguration," +
" alertLevel," +
" MAX(date) AS max_date" +
" FROM" +
" alert" +
" WHERE" +
" subject.id IN (:subjectIds) AND alertConfiguration.id.id IN (:alertConfigurationIds)" +
" GROUP BY" +
" subject, alertConfiguration, alertLevel) AS latest_alerts" +
" INNER JOIN" +
" alert" +
" ON" +
" alert.date = latest_alerts.max_date" +
" AND alert.subject = latest_alerts.subject" +
" AND alert.alertConfiguration = latest_alerts.alertConfiguration" +
" AND alert.alertlevel IN (:alertLevels)" +
" ORDER BY latest_alerts.date DESC")
Page<Alert> findLatest(#Param("subjectIds") List<UUID> subjectIds,
#Param("alertConfigurationIds") List<UUID> alertConfigurationIds,
#Param("alertLevels") List<AlertLevel> alertLevels,
Pageable pageable);
But Hibernate doesn't understand what to do with this to the point where it actually throws a nullpointer while parsing this query.
Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract org.springframework.data.domain.Page ournamespace.sense.repository.AlertRepository.findLatest(java.util.List,java.util.List,java.util.List,org.springframework.data.domain.Pageable)!
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:93)
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:63)
... many more
Caused by: java.lang.NullPointerException
at org.hibernate.hql.internal.antlr.HqlBaseParser.identPrimary(HqlBaseParser.java:4355)
at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:993)
at org.hibernate.hql.internal.antlr.HqlBaseParser.atom(HqlBaseParser.java:3549)
Any idea if this kind of query is even possible? With a nullpointer thrown by Hibernate it's a bit hard to see what part of the query is the problem.
Cannot do it with Hibernate. From the documentation:
Note that HQL subqueries can occur only in the select or where
clauses.
But you can use native query:
#Query(
value = "SELECT latest_alerts.subject_id,
latest_alerts.alertconfiguration_id_id,
latest_alerts.alert_level,
latest_alerts.maxdate ...
FROM ...",
nativeQuery = true)
Page<Alert> findLatest(#Param("subjectIds") List<UUID> subjectIds,
#Param("alertConfigurationIds") List<UUID> alertConfigurationIds,
#Param("alertLevels") List<AlertLevel> alertLevels,
Pageable pageable);

Sql column alias not working in Ebeans rawsql

I am facing strange issue with raw SQLs, and I need some help to figure out the best way to fix it. I could, of course, add the columnMappings, but I want to make sure it's not because I am doing something wrong.
Play Framework APP
Ebeans ORM
Postgresql 9.,4
Executing the following RawSQL against a Postgresql database fails if I don't define columnMappings, although I have an alias defined:
String sql
= " Select date_trunc('day', end_time) as theDate, "
+ " count(*) as value "
+ " From ebay_item "
+ " group by date_trunc('day', end_time) ";
RawSql rawSql =
RawSqlBuilder
.parse(sql)
.create();
Error:
016-03-25 12:05:15,303 ERROR m.c.a.e.s.p.SimpleDBPromiseService - Error executing named query
javax.persistence.PersistenceException: Property [dateTrunc('day'] not found on models.com.abiesolano.ebay.sqlpojos.RangedDateCounter
If I switch to an H2 database:
String sql
= " SELECT trunc(end_time) as theDate, "
+ " count(*) as value "
+ " From ebay_item "
+ " Group by trunc(end_time)";
RawSql rawSql =
RawSqlBuilder
.parse(sql)
.create();
it works no problems.
Any suggestion would be really appreciated.
I don't think mysql likes to group or order by functions, you should use your alias "theDate" instead.
Note that if you're mapping to a bean object, the alias must be a #Transient property of your bean to be mapped by Ebean (otherwise, you'll get an unknown property error).

ADO.NET working with SQL and database

I'm getting an exception error saying missing operators can anyone help
string sql = "Select SalesPerson.Name, Item.Description, Orders.Quantity, Orders.OrderDate"
+ "From([Orders]"
+ "Inner Join[SalesPerson] On Orders.SalesPersonID=SalesPerson.SalesPersonID)"
+ "Inner Join[Item] On Orders.ItemNumber=Item.ItemNumber"
+ "Where Orders.CustomerID=#customer Order by Orders.OrderDate DESC";
You need to add some spaces at the end of each of your lines of SQL!
string sql = "SELECT SalesPerson.Name, Item.Description, Orders.Quantity, Orders.OrderDate "
+ "FROM [Orders] "
+ "INNER JOIN [SalesPerson] ON Orders.SalesPersonID = SalesPerson.SalesPersonID "
+ "INNER JOIN [Item] ON Orders.ItemNumber = Item.ItemNumber "
+ "WHERE Orders.CustomerID = #customer "
+ "ORDER BY Orders.OrderDate DESC";
Otherwise, your SQL ends up being
Select ..... Orders.OrderDateFROM([Orders]Inner Join[SalesPerson] .....
and so on - and that's just not valid SQL.
I also removed some unnecessary parenthesis around the JOIN operators - those are only needed for MS Access, but since you're saying you're using ADO.NET, I assume this is not for MS Access and therefore, those parenthesis are not needed

DB2 syntax when running H2 (in DB2 mode)

I have the following query which works nice when running directly against DB2:
String sql =
"select slutt_dato + 1 day as tDato from klv80201 " +
"union " +
"select fra_dato as tDato from klv12101 where avtalenr = :avtalenr and kundenr = :kundenr " +
"union " +
"select fra_dato as tDato from klv12401 where avtalenr = :avtalenr and kundenr = :kundenr and MEDLEMSTATU < '32' " +
"order by tDato desc fetch first 1 rows only;";
But when I run it through a test with H2 as database with the following configuration:
jdbc:h2:mem:play;MODE=DB2;LOCK_TIMEOUT=10000;LOCK_MODE=0
I get the following error message:
org.h2.jdbc.JdbcSQLException: Column "SLUTT_DATO" not found; SQL
statement: select slutt_dato + 1 day as tDato from klv80201 union
select fra_dato as tDato from klv12101 where avtalenr = ? and kundenr
= ? union select fra_dato as tDato from klv12401 where avtalenr = ? and kundenr = ? and MEDLEMSTATU < '32' order by tDato desc fetch first
1 rows only; [42122-149]
If I remove the "+1 day" the query works nice in H2. The error message from the H2 JDBC driver is wrong, column "SLUTT_DATO" does exist and works nice when removing "+1 day".
Any good suggestions why H2 acts like it does? Is it a bug or is it me that misunderstands something?
Thanks in advance
H2 doesn't understand + 1 day and gets confused here. This will work however:
"select slutt_dato + 1 as tDato from klv80201 "
But I'm afraid this will no work for IBM DB2... I don't think there is an easy solution to this problem that works on both IBM DB2 and H2.