Android ormlite query sort by another table - java

I want to query my data from A and order-by a field from B, The field in B could be null. Any suggestions? Thanks.

As of version 4.22, ORMLite now supports simple JOIN query syntax. Here is the documentation for it:
http://ormlite.com/docs/join-queries
So your query might be something like:
QueryBuilder<B, Integer> bQb = bDao.queryBuilder();
bQb.orderBy("someBField", true);
QueryBuilder<A, Integer> aQb = aDao.queryBuilder();
List<A> results = aQb.join(bQb).query();
You can also certainly use the dao.queryRaw() methods to construct you own query. Here a good example how you would formulate the query:
SQL order by a column from another table

Related

QueryDsl - How create inner join with sorted and grouped table

I have to find Salesmen that have sold some itemType. I created method (see below).
But client told me that he wants to find Salesmen by LAST sold itemType.
DB schema:
My attempts: we have in table ORDERS date column, so in normal SQL query I can do double subquery and it should work.
Double, because first I'm sorting by date, then group by salesman - that returns list with only last sold items.
SELECT *
FROM SALESMEN
JOIN
(SELECT *
FROM
(SELECT *
FROM ORDERS
ORDER BY ORDERS.date)
GROUP BY ORDERS.salesman_id) ON SALESMEN.id = ORDERS.salesman_id
WHERE ORDERS.item_type = "CAR"
Unfortunately, queryDSL can do subquery only in IN clause not in FROM.
I spend many hours to find a solution, and in my opinion, it's simply impossible using queryDSL to get sorted and grouped list and join it with another table in one query.
But maybe someone with grater experience has any idea, maybe a solution is simpler than I think :D
public List<SalesmanEntity> findSalesman(SalesmanSearchCriteriaTo criteria) {
SalesmanEntity salesmanEntity = Alias.alias(SalesmanEntity.class);
EntityPathBase<SalesmanEntity> alias = Alias.$(salesman);
JPAQuery<SalesmanEntity> query = new JPAQuery<SalesmanEntity>(getEntityManager()).from(alias);
... a lot of wird IF's....
if (criteria.getLastSoldItemTyp() != null) {
OrderEntity order = Alias.alias(OrderEntity.class);
EntityPathBase<OrderEntity> aliasOrder = Alias.$(order);
query.join(aliasOrder)
.on(Alias.$(salesman.getId()).eq(Alias.$(order.getSalesmanId())))
.where(Alias.$(order.getItemTyp()).eq(criteria.getLastSoldItemTyp()));
}
return query.fetch();
}
Environment:
Java 1.8
SpringBoot 2.0.9
QueryDSL 4.1.4
This is not a limitation of QueryDSL, rather it is a limitation of JPQL - the query language of JPA. For example, SQL does allow subqueries in the FROM clause, and as such querydsl-sql also allows it. With plain plain JPA, or even Hibernate's proprietary HQL it cannot be done. You would have to write a native SQL query then. For this you can have a look at #NamedNativeQuery.
It is possible to add subqueries on top of JPA using Common Table Expressions (CTE) using Blaze-Persistence. Blaze-Persistence ships with an optional QueryDSL integration as well.
Using that extension library, you can just write the following:
QRecursiveEntity recursiveEntity = new QRecursiveEntity("t");
List<RecursiveEntity> fetch = new BlazeJPAQuery<>(entityManager, cbf)
.select(recursiveEntity)
.from(select(recursiveEntity)
.from(recursiveEntity)
.where(recursiveEntity.parent.name.eq("root1"))
.orderBy(recursiveEntity.name.asc())
.limit(1L), recursiveEntity)
.fetch();
Alternatively, when using Hibernate, you can map a Subquery as an Entity, and then correlate that in your query. Using this you can achieve the same result, but you won't be able to reference any outer variables in the subquery, nor will you be able to parameterize the subquery. Both of these features will however be available with the above approach!
#Entity
#Subselect("SELECT salesman_id, sum(amount) FROM ( SELECT * FROM ORDERS ORDER BY ORDERS.date ) GROUP BY ORDERS.salesman_id")
class OrdersBySalesMan {
#Id #Column(name = "salesman_id") Long salesmanId;
#Basic BigDecimal amount; // or something similarly
}
And then in your query:
.from(QSalesman.salesman)
.innerJoin(QOrdersBySalesMan.ordersBySalesMan)
.on(ordersBySalesMan.salesmanId.eq(salesman.id))

Using a java method in select query jooq

I have a mysql query which is in the following format
dslContext
.select(
ITEMDATA.ITEMID,
ITEMDATA.COST,
ITEMNAMES.ITEMNAME
)
.from(ITEMDATA)
.join(ITEMNAMES)
.on(ITEMDATA.ITEMID=ITEMNAMES.ITEMID)
.where(conditions);
The above query joins ITEMDATA with ITEMNAMES table to select ITEMNAME in the result. I am caching ITEMNAMES table in-memory and want to avoid the join with ITEMNAMES table. This would speed up the query and would simplify the query since the actual query is much more complex.
I would like to use it something similar to the following. I want to call itemNamesCache.getItemName in the select params list which gives the ITEMNAME and returns a part of the select result. getItemName should take the ITEMID returned in the response as a parameter and give the ITEMNAME.
dslContext.
select(
ITEMDATA.ITEMID,
ITEMDATA.COST,
itemNamesCache.getItemName(valueOfItemId)
)
.from(ITEMDATA)
.where(conditions);
P.S: I can iterate the results and call the itemNamesCache.getItemName. But I would like to use something embedded in the query if it's possible
You cannot have a callback from a SQL query back into some Java logic, even if the fact that you're constructing the SQL query with jOOQ (and thus Java) makes it look like that were feasible.
However, you could post-process the jOOQ result by patching records using a previously built cache:
A Java solution
In case you're working with a database that really can't handle this simple join (and you've checked that you have all proper indexes and constraints in place!) then you could try the following solution:
// Assuming this import:
import static org.jooq.impl.DSL.*;
write...
Map<Integer, String> itemNamesCache =
dslContext.selectDistinct(ITEMNAMES.ITEMID, ITEMNAMES.NAME)
.from(ITEMNAMES)
.fetchMap(ITEMNAMES.ITEMID, ITEMNAMES.NAME);
dslContext
.select(
ITEMDATA.ITEMID,
ITEMDATA.COST,
// create an empty column here
inline(null, String.class).as(ITEMNAMES.NAME))
.from(ITEMDATA)
.where(conditions)
// fill the empty column with cached values
.fetch(r -> r.value3(itemNamesCache.get(r.value1())));
A SQL-based solution
The SQL way to do that would be to write a correlated subquery.
SELECT
itemdata.itemid,
itemdata.cost,
(SELECT itemnames.name FROM itemnames WHERE itemnames.itemid = itemdata.itemid)
FROM
itemdata
WHERE
...
With jOOQ
// Assuming this import:
import static org.jooq.impl.DSL.*;
... write:
dslContext
.select(
ITEMDATA.ITEMID,
ITEMDATA.COST,
field(select(ITEMNAMES.NAME)
.from(ITEMNAMES)
.where(ITEMDATA.ITEMID.eq(ITEMNAMES.ITEMID)))
.as(ITEMNAMES.NAME)
)
.from(ITEMDATA)
.where(conditions)
.fetch();
In theory, both queries should run at exactly the same speed, because they're equivalent (if you have a foreign key on ITEMDATA.ITEMID).
In practice, most databases will probably have better performance for the JOIN query, unless they implement scalar subquery caching (e.g. like Oracle), which can drastically speed up the second query, depending on the number of distinct ITEMIDs (the smaller, the better).

pass a array in querybuilder in statement

I am using a query builder to create a query statement in hibernate. i need to pass a arrayList for in statement. How can this be done.
Dummy code :
List<String> xyz = new ArrayList<String>("sam","tam","vam");
StringBuilder queryBuilder = new StringBuilder("select abc from tem where xyz in :xyzList");
Query query = entityManager.createNativeQuery(queryBuilder.toString());
query.setParameter("xyzList", xyz);
query.getResultList();
this is not working. it throws exceptions. Can somebody point me how to do this.
Use setParameterList("xyzList", new String []{"a","b","c"});
So if you have the list with you, you can do list.toArray() in place of new String []{"a","b","c"}
You have seemed to be mistaken an entityManager.createNativeQuery with entityManager.createNamedQuery or entityManager.createQuery
The syntax of your query is JPQL, but you compile it as a native query syntax
What should work for you is to move from createNativeQuery simply to createQuery, or align it the other way around so write a proper native query if that is your goal.
Note just that if you're intent was to go for a native query you should stay away from the named parameters. In your case it would work since you're using hibernate as persistence provider, but otherwise, named parameters in native queries are not supported according to JPA specification

How to create sqlite prepared statement in OrmLite?

Is it possible to create a sqlite prepared statement in OrmLite?
If so, how to bind the query values which may change across different queries.
Is it possible to create a sqlite prepared statement in OrmLite?
You need to RTFM since ORMLite's online documentation is pretty extensive. If you look in the index for "prepared statement" you find out about the QueryBuilder which #Egor pointed out.
how to bind the query values which may change across different queries.
A little further in that section you learn about select arguments which is how you bind query values that change across queries. This is in the index under "arguments to queries".
To quote from the docs here's how you prepare a custom query:
QueryBuilder<Account, String> queryBuilder = dao.queryBuilder();
Where<Account, String> where = queryBuilder.where();
SelectArg selectArg = new SelectArg();
// define our query as 'name = ?'
where.eq("name", selectArg);
// prepare it so it is ready for later query or iterator calls
PreparedQuery<Account> preparedQuery = queryBuilder.prepare();
When you are ready to run the query you set the select argument and issue the query:
selectArg.setValue("foo");
List<Account> accounts = dao.query(preparedQuery);
Later, you can set the select argument to another value and re-run the query:
selectArg.setValue("bar");
accounts = accountDao.query(preparedQuery);

How do I access multiple fields in a JPA query?

I have a JPA query of the form:
SELECT category, count(*) AS c FROM ...
I know that if the query just returns a single column I can do something like:
List<Article> articles = query.getResultList();
However, how do I access the results when there are 2 or more columns as in the example above?
check out section 14.6 here: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html#queryhql-select
it will return a List of Object[] if you select more than one column, but dont get the actual entity.

Categories

Resources