HQL / JPQL - Nested select on FROM - sql

I try to convert my SQL query into HQL or JPQL (I want to benefit of the object mapping).
My SQL Request is :
SELECT *
FROM (SELECT bde, MAX(creation_date)
FROM push_campaign GROUP BY bde) temp,
push_campaign pc where pc.bde = temp.bde and pc.creation_date = temp.creation_date;
I try (unsuccessfully) to convert it in JPQL with :
select pc
from (select bde, max(creationDate)
from PushCampaign group by bde) temp,
PushCampaign pc
where pc.bde = temp.bde and pc.creationDate = temp.creationDate
But I got raised :
IllegalArgumentException occured :
org.hibernate.hql.ast.QuerySyntaxException: unexpected token: ( near
line 1, column 16 [select pc from (select id, max(creationDate) from
models.PushCampaign group by bde) temp, models.PushCampaign pc where
pc.id = temp.id]
I read the nested select can only be in select or where clause.
Do you have workarounds to keep the request and benefit of object-mapping ?

Not possible with JPQL or HQL in a single request.
To do this in a single request I propose this :
String campaignToLaunch = "select pc.* from PushCampaign pc ..."
//SQL request which return a resultset compatible with the models.PushCampaign class
Class className = Class.forName("models.PushCampaign");
List<PushCampaign> result = JPA.em()
.createNativeQuery(campaignToLaunch,className)
.getResultList();

this should achive similar results
select pc
from PushCampaign pc
where pc.creationDate =
(select max(creationDate) from PushCampaign inner where inner.bde = pc.bde)

A simple solution could be:
servlet
{
Query q = entityManager.createNativeQuery("SQL");
List<> li = q.getResultList();
#PersistenceContext(unitName="UNIT")
private EntityManager entityManager;
}

Related

Convert a SQL query to hql

I need to convert this query to hql to use it my code :
SELECT DISTINCT
certificate_id , last_scan
FROM
bcs_certificate_instance
ORDER BY
last_scan
LIMIT 5 ;
Who can help please?
select distinct bci.certificate_id , bci.last_scan
from bcs_certificate_instance bci
order by last_scan asc;
And for limit you have to use setMaxResults() funtion on query object before executing it.
A code snippet for this would look like:
Query query = em.createQuery(“select distinct bci.certificate_id , bci.last_scan
from bcs_certificate_instance bci
order by last_scan asc;”);
query.setMaxResults(10);
List resultData = query.getResultList();
Thats it. So that is how you limit the number of records returned by a query in HQL.
Example with #Query annotation:
public interface PersonDao extends EntityDao<Person, Long> {
#Query("select p from Person p where p.age between ?1 and ?2")
QueryResult<Person> findAllByAge(int minAge, int maxAge);
}
Once you have obtained a QueryResult, you can apply further options and restrictions to the query:
List<Person> result = personDao.findAllByAge(18, 65)
.sortAsc(Person_.lastName)
.sortDesc(Person_.age).
.firstResult(10)
.maxResults(10)
.getResultList();
}

HQL syntax error : 'NHibernate.Hql.Ast.ANTLR.QuerySyntaxException'

As a beginner in HQL , I have a SQL query that I'm trying to transform into hql.
select * from (
   select *
   from CORRELATION_VUE
   where film = v_oldidfilm and FILM2 not in (
                           select c.idfilm
                           from cotes c
                           where idclient = v_idclient)
   order by CORRELATION desc
 
 )
 where rownum <= 3;
So in HQL I'm trying this :
ISession s = NHibernateHelper.GetCurrentSession();
ITransaction tx = s.BeginTransaction();
IQuery query = s.CreateQuery(
#"select u from (
select u from vueCorreliser u
where u.film = :idfilm
and u.FILM2 not in (
select c.idfilm from cote c
where c.idclient = :idclient)
order by u.CORRELATION desc)
where rownum <= 3; ")
.SetInt32("idfilm", idfilm)
.SetInt32("idclient", idclient);
IList<Film> result = query.List<Film>();
tx.Commit();
return result;
But I'm receiving a syntax error on the CreateQuery line.
What did I do wrong?
Thank you
Though I consider this a duplicate of this other question from you, here is a separate, more explicit answer here.
hql does not support sub-queries in from statement. (It supports them in other statements, such as in where conditions.) You have to rewrite your query without the sub-query in the from.
Your sub-query seems to be there only for limiting rows count. Remove the row limit from the query, and use .SetMaxResults(yourMaxRowCount) on the HQL query object instead.
There are no needs for the termination statement ; in HQL, and I do not know if it is supported. I think it is not, better remove it.
var query = s.CreateQuery(
#"select u from vueCorreliser u
where u.film = :idfilm
and u.FILM2 not in (
select c.idfilm from cote c
where c.idclient = :idclient)
order by u.CORRELATION desc")
.SetInt32("idfilm", idfilm)
.SetInt32("idclient", idclient)
.SetMaxResults(4);
That should fix the QuerySyntaxException.
By the way, your usage pattern of transaction is not safe. When using locally scoped transactions, always nest them in using for ensuring they are properly closed.
using (var tx = session.BeginTransaction())
{
...
tx.Commit();
return result;
}
Even in case of failure, the transaction will then always be disposed, which causes it to rollback if it were still ongoing.

Entity framework join with a subquery via linq syntax

I'm trying to translate a sql query in linq sintax, but I'm having big trouble
This is my query in SQL
select * FROM dbo.ITEM item inner join
(
select SUM([QTA_PRIMARY]) QtaTotale,
TRADE_NUM,
ORDER_NUM,
ITEM_NUM
from [dbo].[LOTTI]
where FLAG_ATTIVO=1
group by [TRADE_NUM],[ORDER_NUM],[ITEM_NUM]
)
TotQtaLottiGroupByToi
on item.TRADE_NUM = TotQtaLottiGroupByToi.TRADE_NUM
and item.ORDER_NUM = TotQtaLottiGroupByToi.ORDER_NUM
and item.ITEM_NUM = TotQtaLottiGroupByToi.ITEM_NUM
where item.PRIMARY_QTA > TotQtaLottiGroupByToi.QtaTotale
and item.FLAG_ATTIVO=1
How can I translate into linq sintax?
This approach doesn't work
var res= from i in context.ITEM
join d in
(
from l in context.LOTTI
group l by new { l.TRADE_NUM, l.ORDER_NUM, l.ITEM_NUM } into g
select new TotQtaByTOI()
{
TradeNum = g.Key.TRADE_NUM,
OrderNum = g.Key.ORDER_NUM,
ItemNum = g.Key.ITEM_NUM,
QtaTotale = g.Sum(oi => oi.QTA_PRIMARY)
}
)
on new { i.TRADE_NUM, i.ORDER_NUM, i.ITEM_NUM} equals new { d.TradeNum, d.OrderNum, d.ItemNum }
I get this error
The type of one of the expressions in the join cluase is incorrect. Type inference failed in the call to 'Join'
Can you help me with this query?
Thank you!
The problem is Anonymous Type comparison. You need to specify matching property names for your two anonymous type's properties (e.g. first, second, third)
I tried it out, here's an example: http://pastebin.com/hRj0CMzs

NHibernate Criteria generate invalid SQL for Sybase when using Subqueries

the criteria:
var subQuery = DetachedCriteria.For<RecordInfo>();
.Add(Restrictions.Eq("Property1", "some string"))
.Add(Restrictions.EqProperty("Property2", "record.Id"))
.SetProjection(Projections.Max("Id"));
var criteria = session.CreateCriteria(typeof(Record), "record")
.CreateAlias("record.ListOfRecordInfo", "recordInfo")
.Add(Subqueries.PropertyEq("recordInfo.Id", subQuery));
will generate something like this for Sybase ASE 15.5 dialect:
SELECT this_.Record_Id as Record1_2_3
...
FROM Record this_
INNER JOIN Record_Info Record_Info_
ON this_.Record_Id = Record_Info_.Property_2
WHERE Record_Info_.Record_Info_Id =
(
SELECT max(this_0_.Record_Info_Id) as y0_
FROM Record_Info this_0_
WHERE this_0_.Property_1 = #p0
AND this_0_.Property_2 = this_.Record_Id
)
The problem is the as y0_ that was generated, Sybase doesn't allow alias for sub query for the version of Sybase I'm using.
How do I modify my queries so that NHibernate doesn't generate the alias for the sub query?
We can adjust the projection of the subquery with custom SQL statement. So instead of:
var subQuery = DetachedCriteria.For<RecordInfo>();
...
.SetProjection(Projections.Max("Id")); // instead of this
we can do this:
var subQuery = DetachedCriteria.For<RecordInfo>();
...
.SetProjection(Projections.SqlProjection(" MAX(RecordInfoId) " // use this
, new string[] {"ID"}
, new IType[] {NHibernate.NHibernateUtil.Int32}));
We have to use the column name, because we are skipping the NHibernate Property-to-Column (Id to RecordInfoId).
This will avoid the
SELECT max(this_0_.Record_Info_Id) as y0_ replacing it with
SELECT MAX(RecordInfoId) (our custom SQL)

Return a List of typed object via CreateSQLQuery in NHibernate

Been trying to get the following query working for a few hours now and am running out of ideas. Can anyone spot where I'm going wrong. Any pointers much appreciated.
CalEvents = (List<CalEvent>)session.CreateSQLQuery(#"
SELECT *
FROM dbo.tb_calendar_calEvents
INNER JOIN dbo.tb_calEvents
ON (dbo.tb_calendar_calEvents.calEventID = dbo.tb_calEvents.id)
WHERE dbo.tb_calendar_calEvents.calendarID = 'theCalID'"
)
.AddEntity(typeof(CalEvent))
.SetInt64("theCalID", cal.id);
Error:
Kanpeki.NUnit.CalUserTest.Should_return_logged_in_user:
System.ArgumentException : Parameter theCalID does not exist as a
named parameter in [SELECT * FROM dbo.tb_calendar_calEvents INNER JOIN
dbo.tb_calEvents ON (dbo.tb_calendar_calEvents.calEventID =
dbo.tb_calEvents.id) WHERE dbo.tb_calendar_calEvents.calendarID =
'theCalID']
"SELECT * FROM dbo.tb_calendar_calEvents INNER JOIN dbo.tb_calEvents ON (dbo.tb_calendar_calEvents.calEventID = dbo.tb_calEvents.id) WHERE dbo.tb_calendar_calEvents.calendarID = 'theCalID'"
should be
"SELECT * FROM dbo.tb_calendar_calEvents INNER JOIN dbo.tb_calEvents ON (dbo.tb_calendar_calEvents.calEventID = dbo.tb_calEvents.id) WHERE dbo.tb_calendar_calEvents.calendarID = :theCalID"
= 'theCalID' should be written as = :theCalId; :theCalId is how you use named parameters even in Native SQL Queries.
You should remove the query.ExecuteUpdate() call.
Doing the query.List() is enough to issue the query on the session and return the result set.