Case When syntax expression in jooq - java

I am trying to reproduce this MySQL query in jooq
select case
when year(d.date) - p.birth_year < 5 then '<5'
else '5+'
end as age
from partners p join departure d on d.id = p.id
to
this.schema().select(
DSL.decode().value(dateDiff(p.BIRTHDATE , date(d.DATE)))
.when(greaterThan(5), "above 5")
.when(lessThan(5), "under 5")
.otherwise("unknown").as("age"),
.from(p)
.join(d).on(d.ID.eq(p.ID))

What you seem to be looking for is the SQL:2003 simple CASE expression, which allows to form something like "partial predicates" based on the case value, akin to pattern matching in other languages. This is not yet supported in jOOQ, see Issue #3223.
Interestingly, though, your SQL example doesn't use this syntax, nor does it correspond to your suggested jOOQ API usage. I suspect you wanted to use this syntax to avoid repeating the subtraction twice. This could be done also as follows, in SQL:
select
case sign(year(d.date) - p.birth_year - 5)
when -1 then '<5'
when 0 then '5+'
when 1 then '5+'
else 'unknown' end AS age
from partners p join departure d on d.id = p.id
This would translate to:
Partners p = PARTNERS.as("p");
Departure d = DEPARTURE.as("d");
using(configuration)
.select(choose(sign(year(d.DATE).minus(p.BIRTH_YEAR).minus(5)))
.when(inline(-1), val("<5"))
.when(inline( 0), val("5+"))
.when(inline( 1), val("5+"))
.otherwise(inline("unknown"))
.as("age"))
.from(p)
.join(d).on(d.ID.eq(p.ID))
.fetch();
This static import is implied:
import static org.jooq.impl.DSL.*;

Related

join in flexi search is not working with is null keyword

I have a table named as aviationDispute which has 2 columns deliveryId type=aviationdelivery and invoiceId type=AviationB2BDocuments , now when we raise a dispute from post man it will be eith against a delivery or either against an invoice both the columns can never be filled in one dispute .
The main problem is : my flexi query is only working when both the columns are filled , if one is filled and one remains then it does not gives result .
My flexi query is below
select {p:pk} from {AviationDispute as p join AviationB2BDocuments as a on {p:invoiceId}={a:pk} join AviationDelivery as d on {p:deliveryId} = {d:pk}} where ({d:deliveryId} LIKE '%searchTerm%' or {a:invoiceNumber} LIKE '%searchTerm%')
I have tried various combos of is null and is not null with brackets but nothing is working
What you need is left join
select {p:pk} from {
AviationDispute as p
left join AviationB2BDocuments as a on {p:invoiceId}={a:pk}
left join AviationDelivery as d on {p:deliveryId} = {d:pk}
}
where
{d:deliveryId} LIKE '%searchTerm%' or {a:invoiceNumber} LIKE '%searchTerm%'
hope following query would help:
select {p:pk} from {AviationDispute as p join AviationB2BDocuments as a on {p:invoiceId}={a:pk} join AviationDelivery as d on {p:deliveryId} = {d:pk}} where {d:deliveryId} LIKE '%searchTerm%' and {a:invoiceNumber} is null or {a:invoiceNumber} LIKE '%searchTerm%'
deliveryId will never be null in the result, because of natural join

Hibernate Inner Join OneToMany Mapping throws HibernateQueryException

I am new to Hibernate. I have established a OneToMany mapping between User and Expense. I am trying to return expenses for a User for the last week.
This is the MySQL query that I am using.
select SUM(amount) from Expense INNER JOIN User ON Expense.user_id = User.id AND User.username ='testUser' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY;
When I try to use this query in hibernate, I get a HibernateQueryException
String query = "select SUM(amount) from Expense INNER JOIN User ON Expense.user_id = User.id AND user.username ='sarvam' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY";
List list = session.createQuery(query).list();
The error I get is-
Exception in thread "main" org.hibernate.QueryException: outer or full join must be followed by path expression [select SUM(amount) from com.challenge.pojo.Expense INNER JOIN User ON Expense.user_id = User.id AND user.username ='sarvam' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY]
at org.hibernate.QueryException.generateQueryException(QueryException.java:120)
at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103)
at org.hibernate.hql.internal.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:233)
at org.hibernate.hql.internal.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:193)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:150)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:298)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1825)
at com.challenge.dao.ExpenseDAO.getExpensesForLastWeek(ExpenseDAO.java:52)
at com.challenge.dao.ExpenseDAO.getExpensesForLastWeek(ExpenseDAO.java:44)
at com.challenge.dao.Test.main(Test.java:27)
Caused by: org.hibernate.QueryException: outer or full join must be followed by path expression
at org.hibernate.hql.internal.classic.FromParser.token(FromParser.java:253)
at org.hibernate.hql.internal.classic.ClauseParser.token(ClauseParser.java:93)
at org.hibernate.hql.internal.classic.PreprocessingParser.token(PreprocessingParser.java:118)
at org.hibernate.hql.internal.classic.ParserHelper.parse(ParserHelper.java:43)
at org.hibernate.hql.internal.classic.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:223)
... 10 more
Can anyone please help me fix it.
createQuery(String queryString) Create a new instance of Query for the
given HQL query string.
createSQLQuery(String queryString)
Create a new instance of SQLQuery for the given SQL query string.
You're using the first one which expects HQL as an input, for using native SQL you sould use the second one.
String query = "select SUM(amount) from Expense INNER JOIN User ON Expense.user_id = User.id AND user.username ='sarvam' WHERE created >= curdate() - INTERVAL DAYOFWEEK(curdate())+1 DAY AND created < curdate() - INTERVAL DAYOFWEEK(curdate())-1 DAY";
List list = session.createSQLQuery(query).list();
Session Documentation
You might want to take a look at: I can't make a inner join between two tables in hibernate hql query
If using HQL you have to their Object-Oriented style which might look something like this:
String query = "select SUM(amount) from Expense exp INNER JOIN User u ON e.user_id = u.id AND u.username = 'sarvam' ...";
List list = session.createQuery(query).list();
(untested)
Alternatively you can keep using standard SQL syntay if you instead use:
List list = session.createSQLQuery(query).list();
Then you might want to read Chapter 16 of the Hibernate Documentation.
Keep in mind that the SQL dialect depends on the underlying Database. Depending on your Application there might be a different database used on a different system which could break your SQL statements.

dynamic variable value jasper report

I don't know how to title this question and I know it's just a simple and stupid logic need to be sorted out but I can explain what I need. I have a jasper report script and query in which I need a simple calculation based on a value gathered from Query below
SELECT TOTAL, PARTIAL FROM PRICE WHERE TOTAL > 0
now I need this value to be calculated as the expression below in jasper report script
VAR CALC += TOTAL + (PARTIAL) //as partial can be a -ve or +ve value
What's happening currently is that I didn't find a way to do this, whenever I assign value of TOTAL to a variable and try to use it, it always get's the value from Query and calculates, while I need it to be there only once and then perform calculation on it onward. For that I tried to use calculation="First" but that also gives the first value for all the time and continues. I hope I am able to put my problem well, please help
EDIT
QUERY
SELECT RECEIPTS.DATENEW AS DATE,
TICKETS.TICKETID AS TICKETID,
PAYMENTS.PAYMENT AS PAYMENT,
PAYMENTS.METHOD AS METHOD,
PAYMENTS.TOTAL AS TOTAL,
CUSTOMERS.NAME AS NAME,
(SELECT SUM(P.TOTAL) FROM PAYMENTS AS P
INNER JOIN RECEIPTS AS R ON P.RECEIPT = R.ID
INNER JOIN TICKETS AS T ON R.ID = T.ID
INNER JOIN CUSTOMERS AS C ON T.CUSTOMER = C.ID
WHERE C.ID = CUSTOMERS.ID and P.PAYMENT IN ('debt','debtpaid', 'advance', 'cashrefund')) AS CTOTAL
FROM RECEIPTS
INNER JOIN TICKETS ON RECEIPTS.ID = TICKETS.ID
INNER JOIN PAYMENTS ON RECEIPTS.ID = PAYMENTS.RECEIPT
INNER JOIN CUSTOMERS ON TICKETS.CUSTOMER = CUSTOMERS.ID
WHERE
PAYMENTS.PAYMENT IN ('debt', 'debtpaid', 'advance', 'cashrefund')
....
....
WHERE -TOTAL > 0
VARIABLE
<variable name="DUES" class="java.lang.Double" resetGroup="Customer" resetType="Group" calculation="Nothing">
<variableExpression><![CDATA[$F{CTOTAL} + $F{TOTAL}]]></variableExpression>
<initialValueExpression><![CDATA[new Double(0.0)]]></initialValueExpression>
</variable>
OUTPUT
You can define the variable itself in SQL statement like this :-
SELECT SUM(#csum := #csum + TOTAL+PARTIAL)
FROM (SELECT TOTAL, PARTIAL,#csum := 0
FROM PRICE WHERE TOTAL > 0
) a;
See this question and answer

Bad query peformance, selecting few fields is 10x slower than selecting many fields

My team keeps running into a performance problem when using a SQL Server database. First of all, the application is written in Java and utilizes Hibernate. We have some data stored in a database which we can easily and smoothly retrieve, in case we want to select complete objects (like: all or most of the fields in a given table).
This works well, but when we execute a smaller query, it's 10x slower. The most obvious part might be that we just retrieve a small selection of fields (in this example: 3) and use a WHERE-clause with a like in it (which doesn't seem to be the problem when retrieving 84 fields, but when retrieving 3 fields).
Hibernate takes about 7 seconds to finish the simple query compared to about 3,4 seconds with the big one. When running the plain SQL in DbVisualizer, the complex query takes 0.02 seconds for the query and 0.7 seconds to transmit the data. The simple query, run in DbVisualizer, takes a whopping 0.2seconds (10x slower) and then transmits in just about 0.36s (hence, it's less data to be transferred). One might argue that this is still faster than with the big query, but it seems to have some kind of effect on Hibernate performance.
I was joking about it like "Just add additional fields until the damn thing runs fast!", but that doesn't cut it, as both, the fields to be selected and the where clause(s) are going to be user-configured.
The 84-field-query looks like this:
select
locateable0_.Un_ID as Un1_37_,
locateable0_.active as active37_,
locateable0_.code as code37_,
locateable0_.name as name37_,
locateable0_.ClientID as ClientID37_,
locateable0_.equipmentGroup as equipmen7_37_,
locateable0_.SupplierContractID as Supplier8_37_,
locateable0_.orderingCode as ordering9_37_,
locateable0_.expirationDate as expirat10_37_,
locateable0_.purchaseDate as purchas11_37_,
locateable0_.warrantyExpirationAlert as warrant12_37_,
locateable0_.price as price37_,
locateable0_.priceUnit as priceUnit37_,
locateable0_.VatID as VatID37_,
locateable0_.WEAlertJobID as WEAlert16_37_,
locateable0_.barcode as barcode37_,
locateable0_.erpCode as erpCode37_,
locateable0_.description as descrip19_37_,
locateable0_.innerWorksheet as innerWo20_37_,
locateable0_.outerWorksheet as outerWo21_37_,
locateable0_.ContractorCompanyID as Contrac22_37_,
locateable0_.ContractorPersonID as Contrac23_37_,
locateable0_.ManufacturerCompanyID as Manufac24_37_,
locateable0_.ManufacturerPersonID as Manufac25_37_,
locateable0_.ServicerCompanyID as Service26_37_,
locateable0_.ServicerPersonID as Service27_37_,
locateable0_.BudgetID as BudgetID37_,
locateable0_.costObjectId as costObj29_37_,
locateable0_.costKindId as costKindId37_,
locateable0_.TemplateId as TemplateId37_,
locateable0_.openingDate as opening32_37_,
locateable0_.mainClassId as mainCla33_37_,
locateable0_.pictureId as pictureId37_,
locateable0_.productType as product35_37_,
locateable0_.propertiesId as propert36_37_,
locateable0_.ParentID as ParentID37_,
locateable0_.accessDomainId as accessD38_37_,
locateable0_.orderStateType as orderSt39_37_,
locateable0_.orderEventId as orderEv40_37_,
locateable0_.locationId as locationId37_,
locateable0_.siteId as siteId37_,
locateable0_.buildingId as buildingId37_,
locateable0_.storeyId as storeyId37_,
locateable0_.roomId as roomId37_,
locateable0_.cadObjectId as cadObje46_37_,
locateable0_.geoLattitude as geoLatt47_37_,
locateable0_.geoLongitude as geoLong48_37_,
locateable0_.ratingId as ratingId37_,
locateable0_.grossArea as grossArea37_,
locateable0_.grossVolume as grossVo51_37_,
locateable0_1_.floor as floor99_,
locateable0_2_.calculatedArea as calculat2_100_,
locateable0_2_.nominalArea as nominalA3_100_,
locateable0_2_.categoryId as categoryId100_,
locateable0_2_.wingId as wingId100_,
locateable0_2_.areaUnitId as areaUnitId100_,
locateable0_2_.cleaningArea as cleaning7_100_,
locateable0_2_.rentableArea as rentable8_100_,
locateable0_2_.windowSurface as windowSu9_100_,
locateable0_2_.bottomSurface as bottomS10_100_,
locateable0_2_.topSurface as topSurface100_,
locateable0_2_.wallSurface as wallSur12_100_,
locateable0_2_.floorType as floorType100_,
locateable0_3_.areaSize as areaSize101_,
locateable0_3_.areaType as areaType101_,
locateable0_3_.flooring as flooring101_,
locateable0_4_.workplaceNumber as workplac2_102_,
locateable0_4_.workplaceType as workplac3_102_,
locateable0_4_.usingCompanyId as usingCom4_102_,
locateable0_5_.quantity as quantity190_,
locateable0_5_.quantityUnitId as quantity3_190_,
locateable0_6_.inventoryNumber as inventor2_202_,
locateable0_7_.area as area233_,
locateable0_7_.meterValue as meterValue233_,
locateable0_7_.calibrationFactor as calibrat4_233_,
locateable0_7_.areaDomainId as areaDoma5_233_,
locateable0_7_.degreeDayId as degreeDa6_233_,
locateable0_7_.virtualType as virtualT7_233_,
locateable0_7_.differenceFactor as differen8_233_,
locateable0_7_.differenceMasterId as differen9_233_,
locateable0_7_.virtual as virtual233_,
locateable0_7_.startDate as startDate233_,
locateable0_7_.scheduleId as scheduleId233_,
locateable0_.discriminator as discrimi2_37_
from
MNT_Equipments locateable0_
left outer join
Storey locateable0_1_
on locateable0_.Un_ID=locateable0_1_.id
left outer join
Room locateable0_2_
on locateable0_.Un_ID=locateable0_2_.id
left outer join
RoomArea locateable0_3_
on locateable0_.Un_ID=locateable0_3_.id
left outer join
Workplace locateable0_4_
on locateable0_.Un_ID=locateable0_4_.id
left outer join
INV_Product locateable0_5_
on locateable0_.Un_ID=locateable0_5_.id
left outer join
MNT_FacilityProduct locateable0_6_
on locateable0_.Un_ID=locateable0_6_.id
left outer join
EN_ResourceMeter locateable0_7_
on locateable0_.Un_ID=locateable0_7_.id
left outer join
DynamicProperties dynamicpro1_
on locateable0_.propertiesId=dynamicpro1_.id
left outer join
KEYWORDSEARCH tags2_
on dynamicpro1_.id=tags2_.dynamicPropertiesId
left outer join
MNT_Clients client3_
on locateable0_.ClientID=client3_.Un_ID
where
(
locateable0_.accessDomainId is null
or locateable0_.accessDomainId in (
select
uad.domainId
from
PERM_UserAccessDomain uad
join
Users u
on uad.userId = u.Un_ID
where
u.UserName = 'wsc'
and uad.functionId = 2000
)
)
and locateable0_.discriminator in (
'17000', '6010', '6020', '6030', '6035', '6040', '6060', '6070', '6080', '18000', '5010', '6000', '6100', '5000', '9000', '14000', '19000'
)
and (
client3_.Un_ID in (
1012, 1016, 1013, 1014
)
)
and (
locateable0_.productType not in (
18000, 19000
)
)
and locateable0_.active=1
and locateable0_.productType<>6080
and (
upper(tags2_.keyword) like 'B%'
)
The slow 3-field-query looks as follows:
select
locateable0_.Un_ID as col_0_0_,
locateable0_.code as col_1_0_,
locateable0_.name as col_2_0_
from
MNT_Equipments locateable0_
left outer join
DynamicProperties dynamicpro1_
on locateable0_.propertiesId=dynamicpro1_.id
left outer join
KEYWORDSEARCH tags2_
on dynamicpro1_.id=tags2_.dynamicPropertiesId
left outer join
MNT_Clients client3_
on locateable0_.ClientID=client3_.Un_ID
where
(
locateable0_.accessDomainId is null
or locateable0_.accessDomainId in (
select
uad.domainId
from
PERM_UserAccessDomain uad
join
Users u
on uad.userId = u.Un_ID
where
u.UserName = 'wsc'
and uad.functionId = 2000
)
)
and locateable0_.discriminator in (
'17000', '6010', '6020', '6030', '6035', '6040', '6060', '6070', '6080', '18000', '5010', '6000', '6100', '5000', '9000', '14000', '19000'
)
and (
client3_.Un_ID in (
1012, 1016, 1013, 1014
)
)
and (
locateable0_.productType not in (
18000, 19000
)
)
and locateable0_.active=1
and (
upper(tags2_.keyword) like 'B%'
)
The Microsoft SQL Server Management Studio suggests to add an Index for our requested fields, but doing so doesn't help at all. Especially when keeping in mind that the fields to be queried are going to be user configurable and that hibernate will add a huge bonus on top of the time the query and fetch take.
So, what can we do to increase performance to an acceptable level?
I would note that there is a difference in your where clauses, with this in the first:
and locateable0_.productType<>6080
and missing in the second.
Are there possibly a lot more records with this product type in your database? i.e. does your second query return many more rows than the first?

Multiple "Select Case" statements into Aggregate Named Query using EclipseLink

I'm writing a simple query in my java code using eclipselink v2.3.
This query must simply return a String and two integers, nothing strange I think, or at least I thought,
The query I'm building is the following:
q = entityManager.createQuery(
"SELECT new com.myclass.CalculationQueryResult(transits.device.name,"
+ " SUM(case when transits.direction = 1 then 1 else 0 end) ,"
+ " SUM(case when transits.direction = 0 then 1 else 0 end)) from Transits_Log transits "
+ " where transits.device.name in :devices and transits.dateTime >= :startDate"
+ " and transits.dateTime < :endDate group by transits.device.name" + " order by transits.device.name",
CalculationQueryResult.class);
While it, obviuosly works in SQL Server (our native counterpart), this does not work in JPQL.
The two different (SUM -> CASE) clauses were strangely (at least for me that i'm quite new to JPA) equals to each other. So, I decided to take out the native SQL from the JPQL to investigate deeper and the problem was there. The generated SQL is this one:
SELECT t0.Name,
**SUM(CASE WHEN (t1.Direction = 1) THEN 1 ELSE 0 END)** ,
**SUM(CASE WHEN (t1.Direction = 1) THEN 1 ELSE 0 END)** FROM dbo.ZZZ t0,
YYYY t1
WHERE ((((t1.DeviceName IN ('XXXXX'))
AND (t1.DateTime >= {ts '2012-09-24 17:26:48.031'}))
AND (t1.DateTime < {ts '2012-09-24 18:26:48.031'}))
AND (t0.Name = t1.DeviceName)) GROUP BY t0.Name
ORDER BY t0.Name ASC
As you can see, the SQL generated statement are wrong on the first two lines 'cause the first SUM and the second one should be one the opposite of the other while they're not.
Am I doing something extremely wrong? Does JPQL support multiple nested CASE and SUM? Are there any way to circumnavigate the error(if is the case) without having to write directly native SQL code?
That is very odd. Are you sure your JPQL is correct and compile/deployed?
Can you try the 2.4 release?
If it still occurs, please log a bug.

Categories

Resources