UPDATE and JOIN with JPQL - jpa

Tutorials and samples about JPQL always deal with SELECT statement and sometimes, simple UPDATE statements. I need to update a table with a join.
I have simplified my env :
KEY
= id
- counter
APPLET
= id
! key_id (1-1)
DEVICE
= id
! applet_id (1-1)
! user_id (1-n)
USER
= id
- login
A device has a unique applet, which has a unique keyset. But an user can own several devices.
I need to reset the counter of every KEY attached to the USER login "x".
I tried some syntax with UPDATE and JOIN, without success. Any clue ?
Thank you.

What did you try and what error did you get? What is your object model?
Perhaps something like,
Update Key k set k.counter = 0 where exists (Select u from User u join u.devices d where u.login = "x" and d.applet.key = k)
See,
http://en.wikibooks.org/wiki/Java_Persistence/JPQL_BNF#Update
You could also select the objects and reset the counter in memory and commit the changes.

JPQL does not support join operations in bulk update operations.
When you edit query, nativeQuery = true, you can join.
Query should be written according to the fields in the database.
#Transactional
#Modifying
#Query(nativeQuery = true,
value = "UPDATE Team t" +
" SET current = :current " +
" FROM " +
" members," +
" account" +
" WHERE " +
" members.members_id = t.members_id " +
" AND members.account_id = :account " +
" AND t.current = :current_true ")
int updateTeam(
#Param("current") String current,
#Param("account") Long account,
#Param("current_true") Integer current_true);

Related

Pagination in jpa query giving wrong number of elements in a page

I am getting the wrong number of items (different from the page size I am passing). The code is as follows,
Query query = entityManager.createQuery("SELECT new com.one97.one97pay.web.dto.CustomerReportResponseDTO(cw.walletId, cw.balance, cw.isEnabled,ca.isEnabled,ca.accountLockType,ck.isEnabled AS kycStatus,cp.mobile,cp.residentId,cp.ridExpiryDate, ck.kycStatus,ck.kycType,ca.createdOn "
+ ",TRIM(UPPER(CONCAT (cp.firstName,CASE WHEN cp.middelName is NULL THEN '' ELSE CONCAT(' ', cp.middelName) END,CASE WHEN cp.lastName is NULL THEN '' ELSE CONCAT(' ', cp.lastName) END ))), ck.creationDateTime)"
+ " FROM CustomerProfile AS cp JOIN CustomerAuthModel AS ca ON cp.customerId=ca.customerId "
+ " JOIN CustomerWalletModel AS cw ON cp.customerId = cw.customerId "
+ " JOIN CustomerKycModel AS ck ON ck.customerId = cw.customerId"
+ " ORDER BY ck.creationDateTime DESC");
int pageSize = requestDto.getPageSize();
int pageNumber = requestDto.getPageNum();
query.setFirstResult((pageNumber-1) * pageSize);
query.setMaxResults(pageSize);
List <CustomerReportResponseDTO> customerReportLst = query.getResultList();
I have checked through another api without pagination, the number of results are 100+, but when I pass page number as 1 and page size 10, I get 8 elements in return. What am I doing wrong in this or is there any other way of doing this?
By looking at your code i think * pageSize will not come at query.setFirstResult because i think you are saving the page no in setFirstResult so as per that logic write this query.setFirstResult(pageNumber-1);

Incomplete data while fetching through Named Query JPA2.0

I have an entity named ReqestDetail and done association and mapping as below snippet:
#ManyToOne
#JoinColumn(name="STATUS_C")
private StatusCode statusCode;
//bi-directional many-to-one association to RequestAddressDetail
#OneToMany(mappedBy="requestDetail")
private List<RequestAddressDetail> addressDetails;
I have created below Named Query to fetch the details on the basis of address.
TypedQuery<RequestDetail> query = em.createQuery( "SELECT t FROM RequestDetail t" +
" LEFT JOIN t.employeeDetail e " +
" LEFT JOIN t.addressDetails ao " +
" LEFT JOIN t.addressDetails ad " +
" WHERE (e.employeeI IN ( :employeeIds ) ) AND " +
" (ao.postI = :postO AND ao.addressTypeC = :addressTypeO " +
" AND ad.postI = :PostD AND ad.addressTypeC = :addressTypeD )" ,
RequestDetail.class );
However, when I call query.getResultList(), it is only giving me data of RequestDetail Entity but not of the mapping joins I have mentioned in that entity.
Please advise...
why do you think it should give you some joined objects? Your candidate for the query is RequestDetail, so it gives that. If you did a JOIN FETCH then you can fetch other fields, but you haven't done that (so change those LEFT JOIN to LEFT JOIN FETCH) - a JOIN (without FETCH) is simply a convenience way of forming the query.. Alternatively you could set the entity graph to fetch, or set the fetch on the field itself if you wanted those fetching

Updating values in real time Talend

I'm trying to update my data with talend.I'm using tOracleOutput with the option 'update or insert' but my problem is that when there is an update i want to sum the older and the newer value of a row because my app is executing in real time.There is any help? (sorry for my bad english)
You can use a tOracleRow component containing a SQL update statement . Take the new value (from context, row, or globalMap) and use that in the update statement within tOracleRow, adding it to the existing value of the desired record.
Ex
"
UPDATE target_table
SET target_field = target_field " + globalMap.get("newVal") + "
WHERE target_id = " + globalMap.get("id") + "
"

JPQL "DISTINCT" returns only one result

I am confused by DISTINCT in JPQL. I have two JPQL queries identical except for "DISTINCT" in one of them:
String getObjectsForFlow =
"SELECT " +
" se.componentID " +
"FROM " +
" StatisticsEvent se " +
"WHERE " +
" se.serverID IS NOT NULL " +
" AND se.flowID = :uuid " +
" AND se.componentID IS NOT NULL " +
"ORDER BY " +
" se.timeStamp desc ";
String getObjectsForFlowDistinct =
"SELECT DISTINCT " +
" se.componentID " +
"FROM " +
" StatisticsEvent se " +
"WHERE " +
" se.serverID IS NOT NULL " +
" AND se.flowID = :uuid " +
" AND se.componentID IS NOT NULL " +
"ORDER BY " +
" se.timeStamp desc ";
I run a little code to get the results from each query and dump them to stdout, and I get many rows with some duplicates for non-distinct, but for distinct I get only one row which is part of the non-distinct list.
NOT DISTINCT
::: 01e2e915-35c1-6cf0-9d0e-14109fdb7235
::: 01e2e915-35c1-6cf0-9d0e-14109fdb7235
::: 01e2e915-35d9-afe0-9d0e-14109fdb7235
::: 01e2e915-35d9-afe0-9d0e-14109fdb7235
::: 01e2e915-35bd-c370-9d0e-14109fdb7235
::: 01e2e915-35bd-c370-9d0e-14109fdb7235
::: 01e2e915-35aa-1460-9d0e-14109fdb7235
::: 01e2e915-35d1-2460-9d0e-14109fdb7235
::: 01e2e915-35e1-7810-9d0e-14109fdb7235
::: 01e2e915-35e1-7810-9d0e-14109fdb7235
::: 01e2e915-35d0-12f0-9d0e-14109fdb7235
::: 01e2e915-35b0-cb20-9d0e-14109fdb7235
::: 01e2e915-35a8-66b0-9d0e-14109fdb7235
::: 01e2e915-35a8-66b0-9d0e-14109fdb7235
::: 01e2e915-35e2-6270-9d0e-14109fdb7235
::: 01e2e915-357f-33d0-9d0e-14109fdb7235
DISTINCT
::: 01e2e915-35e2-6270-9d0e-14109fdb7235
Where are the other entries? I would expect a DISTINCT list containing eleven (I think) entries.
Double check equals() method on your StatisticsEvent entity class. Maybe those semantically different values returns same when equals() is called hence producing this behavior
The problem was the "ORDER BY se.timeStamp" clause. To fulfill the request, JPQL added the ORDER BY field to the SELECT DISTINCT clause.
This is like a border case in the interplay between JPQL and SQL. The JPQL syntax clearly applies the DISTINCT modifier only to se.componentID, but when translated into SQL the ORDER BY field gets inserted.
I am surprised that the ORDER BY field had to be selected at all. Some databases can return a data set ORDERed by a field not in the SELECTion. Oracle can do so. My underlying database is Derby -- could this be a limitation in Derby?
Oracle does not support SELECT DISTINCT with an order by unless the order by columns are in the SELECT. Not sure if any databases do. It will work in Oracle if the DISTINCT is not required (does not run because rows are unique), but if it needs to run you will get an error.
You will get, "ORA-01791: not a SELECTed expression"
If you are using EclipseLink this functionality is controlled by the DatabasPlatform method,
shouldSelectDistinctIncludeOrderBy()
You can extend your platform to return false if your database does not require this.
Still, I don't see how adding the TIMESTAMP will change the query results?
Both queries are incorrect JPQL queries, because ORDER BY clause refers to the item that is not on select list. JPA 2.0 specification contains example that matches to this case:
The following two queries are not legal because the orderby_item is
not reflected in the SELECT clause of the query.
SELECT p.product_name
FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c
WHERE c.lastname = ‘Smith’ AND c.firstname = ‘John’
ORDER BY p.price
SELECT p.product_name
FROM Order o, IN(o.lineItems) l JOIN o.customer c
WHERE c.lastname = ‘Smith’ AND c.firstname = ‘John’
ORDER BY
o.quantity
Of course it would be nicer if if implementation could give clear error message instead of trying to guess what is expected result of incorrect query.

TSQL Summary by account, what is the cleanest way to approach this?

I am trying to total by account, the expenses & income per account. There are multiples of both the income & the expenses per account. I am struggling with this as am still learning SQL and thought that someone else likely has already addressed this? I sure would appreciate the help!
I know that this SQL server code is not correct but it at least gives a bit clearer picture of what I am attempting to do.
IF(SELECT(OBJECT_ID('TEMPDB..#Total'))) IS NOT NULL DROP TABLE #Total
declare #Expenses decimal(13,2),
#income decimal(13,2)
set #expenses = sum(EXP_CHILD_CARE_AMOUNT)
+ sum(EXP_FOOD_AMOUNT)
+ sum(EXP_LIFE_INSURANCE_AMOUNT)
+ sum(EXP_TRANSPORTATION_AMOUNT)
+ sum(EXP_TUITION_AMOUNT)
+ sum(EXP_USER_2_AMOUNT)
+ sum(EXP_USER_3_AMOUNT)
+ sum(EXP_UTILITIES_AMOUNT)
set #income = (sum(NET_PAY_AMOUNT)
+ sum(OTHER_INCOME_AMOUNT)
SELECT F.LOAN_NUMBER, #Income, #Expenses
INTO #Total
FROM OPENQUERY(SvrLink, '
SELECT F.Account, #Income, #Expenses
FROM finances F
inner join account a on(a.Account = f.Account)
where a.balance > 0
FETCH ONLY WITH UR ')
...ok, assuming that some fields are grouped into the same table (if not you'll just have to write the joins), you just need 1 query. (I wish all languages were as concise...)
#AccountId is your desired account id.
SELECT l.LOAN_NUMBER, l.AccountId,
(SELECT sum(EXP_CHILD_CARE_AMOUNT) + sum(EXP_FOOD_AMOUNT) +
sum(EXP_LIFE_INSURANCE_AMOUNT) + sum(EXP_TRANSPORTATION_AMOUNT) +
sum(EXP_TUITION_AMOUNT) + sum(EXP_USER_2_AMOUNT) +
sum(EXP_USER_3_AMOUNT) + sum(EXP_UTILITIES_AMOUNT)
as ExpenseTotal FROM Expenses_Guessing_The_Table_Name
WHERE AccountId = #AccountId) as ExpenseTotal,
(SELECT sum(NET_PAY_AMOUNT) + sum(OTHER_INCOME_AMOUNT) as IncomeTotal
FROM Income_Guessing_The_Table_Name
WHERE AccountId = #AccountId) as IncomeTotal
FROM Loans l
WHERE l.AccountId = #AccountId AND l.Balance > 0