I'm new with this API and I'm having some problems with a subquery. I'm using QueryDsl - JPA. I have two tables e.g. Film and Producer. In Producer table I have a primary key producer_id and in my Film table I also have this field as producer_id and it's connected. My goal is to count number of film entity for specific producer using QueryDsl.
I wrote something like it:
QFilm film = QFilm.film;
QProducer producer = QProducer.producer;
createQuery().from(film, producer).select(film.count())
.where(film.producerId.eq(producer.producerId)).fetch();
I'm getting a sum of all matching results, e.g. in Producer table I have 2 producers, and in Film table I have 4 films. First producer have 2 films, and second also have 2. Result of this query is 4. But I want for this particular query to return only 2 for first producer, and only 2 for second one. How to archive this?
You are not mentioning what is the relationship between the two db fields(OneToMany, OneToOne e.t.c). Also you are declaring a QFilm and QProducer instance without actually using them in the query.
Assuming that there is OneToOne relationship between producer.producer_id - film.producer_id and you are using the Querydsl's generated metamodel classes I would try this:
QFilm qFilm = QFilm.film;
long count = creatyQuery().selectFrom(qFilm).where(qFilm.producerId.eq(yourDesiredProducerId)).fetchCount();
Related
I have three tables in my database, SUBSCRIPTION, USER_ID, and an association table called SUBSCRIPTION_USER_ID.
My strategy is to use JOOQ batch with three queries, the first one to insert on row into SUBSCRIPTION, the second query to insert multiple rows into USER_ID, and finally, I need to insert the association IDs into SUBSCRIPTION_USER_ID, so I did the following:
InsertValuesStep2 insertUserIds = insertInto(
USER_ID, USER_ID.USER_ID_TYPE, USER_ID.USER_ID_VALUE);
for (String userId : subscriptionDTO.getUserId())
insertUserIds = insertUserIds.values(getValue(0, userId), getValue(1, userId));
InsertReturningStep insertReturningUserIds = insertUserIds.onConflictDoNothing();
InsertResultStep insertReturningSubscription = insertInto(SUBSCRIPTION)
.set(SUBSCRIPTION.CHANNEL_ID, subscriptionDTO.getChannel())
.set(SUBSCRIPTION.SENDER_ID, subscriptionDTO.getSenderId())
.set(SUBSCRIPTION.CATEGORY_ID, subscriptionDTO.getCategory())
.set(SUBSCRIPTION.TOKEN, subscriptionDTO.getToken())
.onConflictDoNothing()
.returningResult(SUBSCRIPTION.ID);
Unfortunately, to insert values into the association table, I tried many ways but nothing works for me, finally, I tried to insert values in SUBSCRIPTION_USER_IDusing with select but It doesn't work:
InsertValuesStep insertValuesSubscriptionUserIds = insertInto(
SUBSCRIPTION_USER_ID,
SUBSCRIPTION_USER_ID.SUBSCRIPTION_ID,
SUBSCRIPTION_USER_ID.USER_ID_ID)
.select(select(SUBSCRIPTION.ID, USER_ID.ID)
.from(SUBSCRIPTION)
.innerJoin(USER_ID)
.on(concat(USER_ID.USER_ID_TYPE,
val(CATEGORY_USER_ID_DELIMITER),
USER_ID.USER_ID_VALUE).in(subscriptionDTO.getUserId())
.and(SUBSCRIPTION.SENDER_ID.equal(subscriptionDTO.getSenderId()))
.and(SUBSCRIPTION.CHANNEL_ID.equal(subscriptionDTO.getChannel()))
.and(SUBSCRIPTION.CATEGORY.equal(subscriptionDTO.getCategory()))
.and(SUBSCRIPTION.TOKEN.equal(subscriptionDTO.getToken()))));
Am I missing something above? Is there a better way using JOOQ to insert many-to-many relationship values or to use queries results as parameters for other queries?
I'm assuming you posted your entire code. In case of which:
You don't call execute on your USER_ID insertion
Simply add
insertUserIds.onConflictDoNothing().execute();
Or alternatively, fetch the generated IDs using a call to returning().fetch()
Inner join
This might just be a stylistic question, but what you seem to be doing is a cross join. Your INNER JOIN filters aren't really join predicates. I'd put them in the WHERE clause. Clarity may help avoid further problems in such a query.
Specifically, that first "join predicate" is very confusing, containing a CONCAT call, which isn't something one would see in an INNER JOIN every day, and only touches one table, not both:
.on(concat(USER_ID.USER_ID_TYPE,
val(CATEGORY_USER_ID_DELIMITER),
USER_ID.USER_ID_VALUE).in(subscriptionDTO.getUserId())
Wrong predicate
That last predicate seems wrong. You're inserting:
.set(SUBSCRIPTION.TOKEN, subscriptionDTO.getToken())
But you're querying
.and(SUBSCRIPTION.TOKEN.equal(subscriptionDTO.getContactId()))));
That should probably be subscriptionDTO.getToken() again
As mentioned above, I have inserted values for SUBSCRIPTION and USER_ID tables. And get for the association table I need to get the IDs of the already inserted values from the above two tables, so to solve the issue I've used this query to insert in SUBSCRIPTION_USER_ID:
InsertReturningStep insertReturningSubscriptionUserId = insertInto(
SUBSCRIPTION_USER_ID,
SUBSCRIPTION_USER_ID.SUBSCRIPTION_ID,
SUBSCRIPTION_USER_ID.USER_ID_ID)
.select(select(SUBSCRIPTION.ID, USER_ID.ID).from(SUBSCRIPTION
.where(concat(USER_ID.USER_ID_TYPE, val(CATEGORY_USER_ID_DELIMITER), USER_ID.USER_ID_VALUE).in(subscriptionDTO.getUserId()))
.and(SUBSCRIPTION.SENDER_ID.equal(subscriptionDTO.getSenderId()))
.and(SUBSCRIPTION.CHANNEL_ID.equal(subscriptionDTO.getChannel()))
.and(SUBSCRIPTION.CATEGORY.equal(subscriptionDTO.getCategory()))
.and(SUBSCRIPTION.TOKEN.equal(subscriptionDTO.getToken()))).onConflictDoNothing();
Finally, I have executed all the queries using batch:
using(configuration).batch(insertReturningSubscription,
insertReturningUserIds,
insertReturningSubscriptionUserId).execute()
I have multiple charts in a page which will be updated with values from database.
I am making an ajax call when chart is initialized, now the request comes to controller class.
From controller class I am making multiple call to database using repository class object.
How can I make a single request to database with multiple queries and get array of response.
For e.g. Here I have made a 3 different calls to get 3 different value for a chart:
Controller Class and Repository class
How can I combine these request into single one.
There is a concept of Batching in JDBC where we can use addBatch and excuteBatch to do what I wanted, but I am not able to understand if I can achieve the same using Spring batch.
Sounds like you want to implement these as async queries.
This is covered in the Spring Data JPA documentation, I believe. You can use any of these method formats in the current version:
#Async
Future<User> findByFirstname(String firstname);
#Async
CompletableFuture<User> findOneByFirstname(String firstname);
#Async
ListenableFuture<User> findOneByLastname(String lastname);
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-async
(You could also spin off separate Thread instances for each, but I wouldn't advise it)
Statement.addBatch is not supposed to be used for SELECT but for batching INSERTs and UPDATEs
What you need is a bit of a Custom query with UNION to get all the data you need in one sql.
SELECT COUNT(n.lastUpdatedOn)
FROM TableEntity n
WHERE n.lastUpdatedOn BETWEEN :start1 AND :end1
UNION
SELECT COUNT(n.lastUpdatedOn)
FROM TableEntity n
WHERE n.lastUpdatedOn BETWEEN :start2 AND :end2
UNION
SELECT COUNT(n.lastUpdatedOn)
FROM TableEntity n
WHERE n.lastUpdatedOn BETWEEN :start3 AND :end3
And your Repository code.
#Query("SELECT COUNT(n.lastUpdatedOn) FROM TableEntity n WHERE n.lastUpdatedOn BETWEEN :start1 AND :end1 UNION SELECT COUNT(n.lastUpdatedOn) FROM TableEntity n WHERE n.lastUpdatedOn BETWEEN :start2 AND :end2 UNION SELECT COUNT(n.lastUpdatedOn) FROM TableEntity n WHERE n.lastUpdatedOn BETWEEN :start3 AND :end3")
List<Long> countModifiedTimeStamp(#Param("start1") Timestamp start1, #Param("end1") Timestamp end1, #Param("start2") Timestamp start2, #Param("end2") Timestamp end2, #Param("start3") Timestamp start3, #Param("end3") Timestamp end3);
And when you call
List<Long> counts = this.repo.countModifiedTimeStamp(todayStartDay, today, last7days, today, longBack, last7days);
In the returned list you will have today at first element, last7days in second and longBack in third.
I'm working with JPA CriteriaBuilder, CriteriaQuery etc. and static metamodels for typesafe queries, like here for example: click.
I have 3 tables: Client, Package, Vegetable.
Every client has 1 or more packages, and those packages contain multiple vegetables.
What I have now:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Client> query = builder.createQuery(Client.class);
Root<Client> root = query.from(Client.class);
ListJoin<Package, Vegetable> join = root.join(Client_.packages).join(Package_.vegetables);
TypedQuery<Client> typedQuery = entityManager.createQuery(query);
return typedQuery.getResultList();
The ListJoin I added recently. Point is what Hibernate does: generates the whole select for all fields in Client class from the Client table inner joined with Package and Vegetable, but it doesn't actually selects those fields from joined tables. It gets every package by ID and then every vegetable by ID, thus doing n+1 selects.
Without the ListJoin it doesn't inner join those tables, but I'm working on it right now so I added those joins. Now I want to select all the fields from those classes so I get whole object hierarchy with 1 select. I tried doing something with projections like in the link I gave in Projecting the result chaper, but I have no idea how to connect that with ListJoin.
Is that even possible in this situation? When I run this query on database (with manually added all the fields from joined tables) it works fine, but would Hibernate handle that? And if so - how to project the result so it selects all the fields from 3 tables joined together and constructs whole object hierarchy, all with 1 select?
//Edit: managed to retrieve all packages with a single query, but going further raises exception:
Root<Client> root = query.from(Root.class);
ListJoin<Client, Package> join = root.join(Client_.packages);
ListJoin<Package, Vegetable> secondJoin = join.join(Package_.vegetables);
root.fetch(Client_.packages);
Naturally, I tried to add: join.fetch(Package_.vegetables); but it raises the org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list, no idea what is that.
As to the latest comment: gonna try that now.
//Edit2: I added 2 fetches (couldn't cast them to Join like in that answer, compiler errors):
Fetch<Client, Package> join = root.fetch(Client_.packages);
Fetch<Package, Vegetable> secondJoin = join.fetch(Package_.vegetables);
It raises org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags, known error I guess so at least got something to search for.
//Edit3: Changed it both to Sets and it works, thanks, couldn't have done it without the Fetch instead of Join suggestion, seems kinda unintuitive to me.
Lets say I have a table like :
CREATE TABLE USER (
userid ascii,
books set<text>
PRIMARY KEY (userid)
);
and index :
create index on USER (books);
I want to query on books by using sql context. What I am doing is :
CassandraSQLContext cassandraContext = new CassandraSQLContext(sparkContext);
SchemaRDD userTable = cassandraContext.sql("SELECT * FROM keyspace.user");
userTable.registerTempTable("usertable");
Following query does not work for Cassandra :
SchemaRDD userTable = cassandraContext.sql("SELECT * FROM keyspace.user where books CONTAINS 'book1' and books CONTAINS 'book2'");
It returns users with only 'book1'. I've tried similar queries like books CONTAINS ('book1', 'book2') but none of them worked.
What I can do on registered table is :
SchemaRDD users = cassandraContext.sql("SELECT * FROM usertable where userid='some_user_id'");
What I want to do is query by books like :
SchemaRDD users = cassandraContext.sql("SELECT * FROM usertable where books IN ('book1', 'book2')");
or similar queries.
but it doesnt work. It returns 0 records. I tried to register index table named as user_books_idx but it didnt work either. Am I able to query on indexed collections? How can i do it?
It seems the CONTAINS clause only works with one value per statement, so you may not be able to 'and' two different CONTAINS clauses together at one shot.
So I would create one RDD using CONTAINS 'book1', then I'd create another RDD using CONTAINS 'book2', and then I'd do a join of the two RDD's on the userid field. That should give you a resulting RDD of the users with both book1 and book2 in their books set.
In my Java Web application I use Postgresql and some data tables are filled automatically in server. In the database I have a STATUS table like below:
I want to select the data related to a vehicle between selected dates and where the vehicle stayed connected. Simply I want to select the data which are green in the above table which means I exactly want the data when firstly io1=true and the data when io1=false after the last io1=true. I have postgresql query statement which exactly gives me the desired data; however, I have to convert it to HQL because of my application logic.
working postgresql query:
WITH cte AS
( SELECT iostatusid, mtstrackid, io1,io2,io3, gpsdate,
(io1 <> LAG(io1) OVER (PARTITION BY mtstrackid
ORDER BY gpsdate)
) AS status_changed
FROM iostatus
WHERE mtstrackid = 'redcar' AND gpsdate between '2014-02-28 00:00:00' and '2014-02-28 23:59:59'
)
SELECT iostatusId, mtstrackid, io1, io2, io3,gpsdate
FROM cte
WHERE status_changed
OR io1 AND status_changed IS NULL
ORDER BY gpsdate ;
How should I convert the above query to HQL or how could I retrieve the desired data with HQL?
The goal of hibernate is mapping database entities to java objects. This kind of complex queries are not entities themselves. This is against the spirit of hibernate.
If this query generates an entity in your application logic, I recommend putting the results into a table and applying Hibernate queries to that table.
If this query generates some kind of aggregation or summary, there are two possible ways:
One way is you compute this aggregation/summary in your application after retrieving entities from iostatus table with hibernate.
If this query has nothing to do with your application logic then you can use Native SQL interface of Hibernate and execute the query directly. (You can even use JPA if you are willing to manipulate two database connections.)
If you absolutely need to convert it to HQL, you need to eliminate the partition function. If the order of iostatusId is identical to the order of gpsdate, you can do it similar to
SELECT i2.*
FROM iostatus i1
INNER JOIN iostatus i2 ON i1.iostatusId = i2.iostatusId - 1
AND i1.io1 <> i2.io1
AND i1.mstrackid = i2.mstrackid
WHERE i2.mtstrackid = 'redcar' AND
i2.gpsdate between '2014-02-28 00:00:00' and '2014-02-28 23:59:59'
If gpsdate is no way related to iostatusId then you need something like
SELECT i2.*
FROM iostatus i1
INNER JOIN iostatus i2 ON i1.gpsdate < i2.gpsdate
AND i1.io1 <> i2.io1
AND i1.mstrackid = i2.mstrackid
WHERE i2.mtstrackid = 'redcar' AND
i2.gpsdate between '2014-02-28 00:00:00' and '2014-02-28 23:59:59' AND
NOT EXISTS (SELECT * FROM iostatus i3
WHERE i3.gpsdate > i1.gpsdate AND
i2.gpsdate > i3.gpsdate AND
i3.io1 = i1.io1 AND
i1.mstrackid = i3.mstrackid)
I guess both of the queries can be converted to HQL, but I'm not positively sure.
By the way I must warn you that, these methods might not perform better then finding the changes in your application, because they involve joining the table onto itself, which is an expensive operation; and the second query involves a nested query after the join, which is also quite expensive.