Is it possible to do the following query in QueryDSL?
SELECT p.*
FROM parts_table p LEFT JOIN inventory_balance_table i ON
(p.part_no = i.part_no
AND i.month = MONTH(CURRENT_DATE)
AND i.year = YEAR(CURRENT_DATE));
Inventory balance stores inventory data for every part number/month/year; I need the only the data for the current year and month.
I've gotten the basic left join down:
QPartsTable qParts = QPartsTable.partsTable;
QInventoryBalance qBalance = QInventoryBalance.inventoryBalance;
JPAQuery q = new JPAQuery(em);
q.from(qParts).leftJoin(qParts.inventoryBalance, qBalance);
q.where(...);
List<Part> list = q.list(qParts);
which makes the correct sql, but only joining on the part number.
The resulting parts are checked for stock availability (among other things). The left join is necessary, because I still need parts that don't have an inventory entry yet (new parts for instance). Left join will get those without a matching inventory balance, but adding month = MONTH(CURRENT_DATE) and so on to where clause of the query removes the rows without an inventory balance (because they don't have year/month data).
For the same reason #Where and #Filter would remove those parts from the resulting parts list and are not applicable. Sadly #Filter and #Where are the only other results I'm getting with a search in Google and here on SO. (Oddly the Filter doesn't even affect the query even if filters are enabled in the session...)
The simplest solution would be my original question: How to turn the above SQL into QueryDSL? In general, is it possible to add more and/or custom conditions to the ON clause of the left join? What are the alternative solutions to this problem?
Thanks in advance!
Update - A follow-up question and an observation: (Perhaps this should be a new question entirely?)
After looking through the docs, it seems the older blogs demonstrating querydsl had the on() function for leftJoin's. Why is this no longer the case?
SQLQuery (or HibernateSQLQuery or some other variety) has the on() function, but leftJoin() accepts RelationalPath<T>, not an EntityPath<T> as JPAQuery does. It seems impossible to cast QClasses to a RelationalPath, so that's probably not the way to go...
Update 2 - We're using 2.9.0. Using on() gives an error, like it doesn't exist...
It is possible to use on() in QueryDSL, including the latest version. JPAQuery also supports on() predicate.
So this can be achieved,
QPartsTable qParts = QPartsTable.partsTable;
QInventoryBalance qBalance = QInventoryBalance.inventoryBalance;
JPAQuery q = new JPAQuery(em);
q.from(qParts).leftJoin(qParts.inventoryBalance, qBalance).on(qBalance.month.eq(yourMonth).and(qBalance.year.eq(yourYear))).list(qParts);
JPAQuery implements JPQLCommonQuery interface, so as others it has all necessary methods.
Here are docs from QueryDSL latest version with left join using on() example.
Update:
on() has been introduced since QueryDsl 3.0.0 version. So for versions below 3.0.0 it is not available.
I'd suggest to upgrade your version at least to 3.0.0, as the API is quite stronger comparing to old versions. Even more, I'd strongly advice to upgrade to the latest stable version (3.6.2), there shouldn't be any problems as new API supports everything as before, with additional features.
Update 2:
As #Cezille07 mentioned in the comment, there is a with() alternative for on(), in older versions. As we see from the issue , with() has been replaced with on() later on.
So for older versions with() does the trick. Here is a usefull link with more details.
Related
Are there any parameters, which can turn on/off execution of next query during jooq code generation?
SELECT "SYS"."ALL_OBJECTS"."OWNER",
"SYS"."ALL_OBJECTS"."OBJECT_NAME",
"SYS"."ALL_OBJECTS"."OBJECT_ID",
"SYS"."ALL_PROCEDURES"."AGGREGATE"
FROM "SYS"."ALL_OBJECTS"
LEFT OUTER JOIN "SYS"."ALL_PROCEDURES"
ON ( "SYS"."ALL_OBJECTS"."OWNER" =
"SYS"."ALL_PROCEDURES"."OWNER"
AND "SYS"."ALL_OBJECTS"."OBJECT_NAME" =
"SYS"."ALL_PROCEDURES"."OBJECT_NAME")
WHERE ( UPPER ("SYS"."ALL_OBJECTS"."OWNER") IN ( 'MYSCHEMA')
AND "SYS"."ALL_OBJECTS"."OBJECT_TYPE" IN ( 'FUNCTION', 'PROCEDURE'))
ORDER BY "SYS"."ALL_OBJECTS"."OWNER" ASC,
"SYS"."ALL_OBJECTS"."OBJECT_NAME" ASC,
"SYS"."ALL_OBJECTS"."OBJECT_ID" ASC
On database with large number of schemas and objects it tooks about one hour to be executed
One major issue with the query run by jOOQ is the UPPER(OWNER) expression. This was introduced with jOOQ 2.4 (#1418) to prevent misconfigurations where users accidentally use lower case schema names. The feature was based on an erroneous assumption that case-sensitive users are impossible. They are certainly possible (even if rare), so #1418 was wrong. I've created two issues for this problem:
#5989: Fix the performance issue by avoiding functions on the OWNER column
#5990: Re-enact case-sensitive schema names
In the meantime, you have some possible workarounds:
Pre jOOQ 3.8
You can always override the JavaGenerator from jooq-codegen and re-implement some methods including generatePackages() and generateRoutines() to be empty. This way, the relevant code will not be executed at all.
Of course, this means you won't get any generated packages and routines.
Post jOOQ 3.8
There is a new configuration option where you can do the same as above configuratively:
<configuration>
<generator>
<database>
<includeRoutines>false</includeRoutines>
<includePackages>false</includePackages>
...
See also:
https://www.jooq.org/doc/latest/manual/code-generation/codegen-advanced/codegen-config-include-object-types
I'm new to hibernate framework and I don't know how to write code using hibernate functions to get needed object. In internet I have seen code using criteria and projection, but the query for projection is not what i need. For example i need to get last version of project by date. This is criteria
Criteria criteria = session
.createCriteria(Assembly.class)
.setProjection(Projections.max("date"));
-First problem is that it gets max value from all table(don't know how to set for searching only exact project name date).
-Second problem that it returns date but i need object of class.
In summary i need from hibernate to generate such query:
SELECT * FROM assembly WHERE projectName = ? AND ...don't know how to finish it, date = max() - won't work as I understand.
One of the bad solution is to get all exact projects and then compare there dates, but I think there's gonna be good solution.
This should work
Assembly newest =
(Assembly) session.createCriteria(Assembly.class)
.add(Restrictions.eq("projectName", projectName))
.addOrder(Order.desc("date"))
.setMaxResults(1)
.uniqueResult();
I am using PlayFramework 2.2.2 with Ebean and MsSql.
I am looking for the simplest or cleanest method to be able to sort by MIN or MAX etc.
A sample raw sql query might look like:
SELECT id, name, tickets FROM users WHERE tickets != NULL ORDER BY MAX(tickets)
I don't know if it's just me, but the documentation for ebean is incredibly confusing. It seems any time anyone comes up with a query that couldn't be written by a 9 year old, the answer is "switch to RawSQL". Well, why bother with Ebean at all then?
Anyway, I would really like to see some CONCRETE Ebean examples of ordering by MIN/MAX, etc.
Do you really need order by min ,max... since there is id in the select list.
Let me know whether id is unique or duplicates are allowed
Would suggest to use the following query incase the id is unique
select id,name,tickets from users where tickets is not null order by ticket desc
I encountered the same problem then I found the following information.
Design Goal:
This query language is NOT designed to be a replacement for SQL. It is designed to be a simple way to describe the "Object Graph" you want Ebean to build for you. Each find/fetch represents a node in that "Object Graph" which makes it easy to define for each node which properties you want to fetch.
Once you hit the limits of this language such as wanting aggregate functions (sum, average, min etc) or recursive queries etc you use SQL. Ebean's goal is to make it as easy as possible to use your own SQL to populate entity beans. Refer to RawSql .
-> http://www.avaje.org/static/javadoc/pub/com/avaje/ebean/Query.html
I am attempting to return a single object via castor query that has the earliest date.
This is the sort of thing I have been trying:
SELECT p FROM model.objects.Product p LIMIT $1 WHERE p.status=$2 ORDER BY p.statusDate;
This results in: org.exolab.castor.jdo.oql.OQLSyntaxException: An incorrect token type was found near WHERE (found KEYWORD_WHERE, but expected END_OF_QUERY
I am using version 0.9.6 which I believe supports this kind of thing.
Any hints or pointers much appreciated.
As per my comment, it indeed appears that the LIMIT clause must appear after the ORDER BY clause. See the Castor query syntax.
I've got an application that uses a hibernate(annotations)/mysql combination for ORM. In that application, I got an entity with a Date field. I'm looking for a way to select on that date within a time range (so hh:mm:ss without the date part).
In MySQL there's a function TIME(expression) that can extract the time part and use that in the where clause, but that does not seem to be available in Hibernate without switching to native queries. Is there an option in hibernate to do this, or should I loop through the results in java and do the comparison there? Would this be much slower as the MySQL solution, since that would not use indexes anyway?
The following functions are available in HQL, maybe you could use them:
second(...), minute(...), hour(...), day(...), month(...), year(...)
Add the expression as a SQL restriction rather than having a full native query. I don't know MySQL specifically, but imagine something like this:
Criteria criteria = session.createCriteria(MyTable.class);
criteria.add(
Expression.sql(
"TIME( {alias}.my_date, 'hh:mm:ss') >= :1",
dateRangeMin,
new StringType()
)
);