I have a table where user_id and parent_user_id is stored. For example:
user_id parent_user_id calls designation
---------------------------------------------------
1 0 10 Tech Support
2 1 5 Sr. Tech Support
3 2 11 Tech Support
4 2 12 Tech Support
5 4 10 Tech Support
Scenario is, if a user who has 2 children with 10 calls each, he will get an designation change like Sr. Tech Support. And If he has 10 such callers, it will be Manager.
To do this so far what I have done(java),
#Override
public boolean updateDesignation(int userId, int depth) {
// check whether maximum depth is reached
if (depth == 0)
return false;
depth--;
int userIds = getIds(userId);//Will get parent_id
String LOCAL_SQL = SQLconstants.getSQL("get-total-calls.sql");
if(userIds>0) {
int calls = jdbcTemplate.queryForObject(LOCAL_SQL, Integer.class, userIds);
// I get 4's calls with which I need to see if I have 2 users with 10 calls each!
updateDesignation(userIds, depth);
}
//updateRanks(userId, depth);
return true;
}
If I pass 5 as user_id, and 4 as depth. It will go till user_id and update values. And how it works is 5->4, 4->2, 2->1. But what I need to achieve is 5->4, and check 4's child's calls. same like 3, 2, 1. How can I do this? Please help me.
if(userIds>=0) { // process 0 too, as it is a parent
/* execute this sql
SELECT COUNT(*) FROM tablename WHERE parent_user_id=userIds AND calls>=10;
then check if the returned value is >= 2 or other chekings...
and update designations..
*/
updateDesignation(userIds, depth);
}
In this way u dont need to get calls of each parent. So this line is not needed anymore:
int calls = jdbcTemplate.queryForObject(LOCAL_SQL, Integer.class, userIds);
Related
How can I update with one query?
I want to do something like this:
update customer
set balance = (400,150) where customer_id IN ('2','3');
customer 2 will get a new balance of 400 and customer 3 will get 150.
I want 1 query because I'm using spring-boot, JPA
#Modifying
#Query("update customer set balance = (400,150) where customer_id IN ('2','3');")
Can I do here 2 queries? for each customer?
what is recommended? what is acceptable?
thanks.
You can do by this way -
Update customer
SET balance = (case when customer_id = '2' then '400'
when customer_id = '3' then '150'
end)
WHERE
customer_id IN ('2','3');
The CASE statement may be what you are looking for.
UPDATE customer
SET balance = (case
when customer_id = 1 then 150
when customer_id = 2 then 300
end)
WHERE ID in (1,2);
If your customer_id is of type string, add quotes to the customer_id numbers.
My example is just a modified version of:
Example Code:
UPDATE students
SET JavaScore = (case
when ID = 1 then 75
when ID = 2 then 80
when ID = 3 then 86
when ID = 4 then 55
end),
PythonScore = (case
when ID = 1 then 70
when ID = 2 then 85
when ID = 3 then 94
when ID = 4 then 75
end)
WHERE ID in (1,2,3,4);
From this website:
DelftStack
Hibernate can do this for you, no need to write your own query.
The steps.
Set hibernate.jdbc.batch_size to some reasonable size.
Enable insert/update query ordering
Enable statement rewrites for MySQL (set rewriteBatchedStatements to true)
In your application.properties add the following
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
# spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true # Needed when using versioned data
spring.datasource.hikari.dataSourcePoperties.rewriteBatchedStatements=true
See also this and this for a bit more background.
Now in your code you can just update and save your customers and the database will receive only 1 query.
if you want to use the spring-data way, you have to use complex SQL/JPQL as less as possible.
#Entity
class CustomerEntity {
}
#Modifying
#Query("update CustomerEntity customer set customer.balance = :balance where customer.id = :customerId")
int updateCustomerBalance(#Param("customerId") String customerId, #Param("balance") String balance);
customerRepository.updateCustomerBalance("2", "400");
customerRepository.updateCustomerBalance("3", "150");
Common transaction
if you want to update happens in one transaction
#Transactional
void doUpdate() {
customerRepository.updateCustomerBalance("2", "400");
customerRepository.updateCustomerBalance("3", "150");
}
Keep in mind that you have to call service.doUpdate() from outside. if you call the method from another service method, transaction will not be created.
Check that update has happened
int count = customerRepository.updateCustomerBalance("2", "400");
if (count == 0) {
log.error("Customer not updated customerId=2 customerBalance=400");
}
I have set and a sub-set for each id. i need to accumulate the total
ex: employeeIdSet is the outer set which has all the employeeIds
Now each employee - may be combined or not combined and they will be added credits
empa - credit 10
empb linked with empc, empd - credit would be 15, overall for the 3 employees.
similalrly
empe linked with empz, emps - credit would be 7, over all for the 3 employees and linked with empq where the credit is 9
similarly
empr linked with empo - credit would be 6, overall for the 2 employees
Now i want to have a list of employee id with respective credits
ex:
empa-10
emp-15,
empc-15,
empd-15,
empe - 7+9,
empz - 7+9,
emps- 7+9,
empr - 6,
empo - 6
the problem we get employee id in the outer loop and inner loop we can get the subsequent employees. however all addition leads to problem
code
final Set<Long> combinedEmployeeIdSet = new HashSet<>();
final Set<CombinedEmployee> combinedEmployees = employee.getCombinedEmployees();
for(final CombinedEmployee combinedEmployee: combinedEmployees) {
combinedEmployeeIdSet.add(combinedEmployee.getId());
}
for(final OtherEmployee otherEmployee: otherEmployees) {
if(!combinedEmployeeIdSet.contains(otherEmployee.getId())) {
employeeCredit += otherEmployee.getCredit();
}
}
expectation is get the total credits of the given employeeId where when there under same group, it should be added as one single unit, else the credit should be added
empe - 7+9, displays 15
empz - 7+9, displays 15
emps- 7+9, displays 15
thanks
Very confused by your description.
Do you mean you have some "emp"s, say: emp-a,emp-b ... emp-x, and each emp have a credit, say: emp-a:10, emp-b:5, emp-c:7... emp-x:6. Some emps have links with other emps, say: emp-a (emp-b, empc). Now you want to get the credit for each emp, if the emp has links, its credit should be a sumarize of itself and all its links.
So you may get
emp-a 10+5+7
emp-b 5
emp-c 7
...
emp-x 6
Recently I started working with Odi12c procedures, until now there was only work with mappings. Now, I have a mapping with different tables and joins, and I need to do calculations by columns. For that, I must use a java method, so I have something like this:
public void static List<Map<String, String>> seg( List<Map<String, String>> comp) {
for (Map<String, String> map : comp) {
if (total > 0 && min1 != min1_fin) {
rest = total - min1;
total-=min1;
map.replace("min1_fin",rest);
map.replace("total",total);
} else {a= true}
if (a) { //(operation for next column)
if (total > 0 && min2 != min2_fin) {
rest = total - min2;
.
..
...
}
return comp;
}
My list:
KEY TOTAL MIN1 MIN2 MIN1_FIN MIN2_FIN
------ -------- -------- ------- --------- ----------
1 35,14 61,85 91,85 0 0
1 35,14 8,09 58,32 0 0
2 85,67 6 6 0 0
2 85,67 67,6 71,47 0 0
I have thought about putting everything in a package and my code in a procedure directly or in a jar and calling it (I still don't know how).
But is it possible to do that? How can I send the data to my java method that way and read it when I return?
Using Java to do the transformation is not the best pattern if the result needs to be stored in a database. Doing it in SQL will be much more efficient.
Anyway, if you really want to use Java you can pass data from the Source command to the Target command of any Procedure step or KM step by binding it. Here is the doc about it : https://docs.oracle.com/cd/E15586_01/integrate.1111/e12643/procedures.htm#CHDGDJGB
Make sure to select the "Multi-Connections" checkbox in the definition of the Produre. The data will pass though the execution agent.
I have a list which is a java object like below.
public class TaxIdentifier {
public String id;
public String gender;
public String childId;
public String grade,
public String isProcessed;
////...///
getters and setters
///....///
}
Records in DB looks like below,
id gender childId grader isProcessed
11 M 111 3 Y
12 M 121 4 Y
11 M 131 2 Y
13 M 141 5 Y
14 M 151 1 Y
15 M 161 6 Y
List<TaxIdentifier> taxIdentifierList = new ArrayList<TaxIdentifier>();
for (TaxIdentifier taxIdentifier : taxIdentifierList) {
}
while I process for loop and get the id = 11, i have to check if there are other records with id = 11 and process them together and do a DB operation and then take the next record say in this case 12 and see if there are other records with id = 12 and so on.
One option is i get the id and query the DB to return all id = 11 and so on.
But this is too much back and forth with the DB.
What is the best way to do the same in java? Please advice.
If you anyway need to process all the records in the corresponding database table - you should retrieve all of them in 1 database roundtrip.
After that, you can collect all your TaxIdentifier records in dictionary data structure and process in whatever way you want.
The brief example may look like this:
Map<String, List<TaxIdentifier>> result = repositoty.findAll().stream().collect(Collectors.groupingBy(TaxIdentifier::getId));
Here all the TaxIdentifier records are grouped by TaxIdentifier's id (all the records with id equals "11") can be retrieved and processed this way:
List<TaxIdentifier> taxIdentifiersWithId11 = result.get("11");
I would leverage the power of your database. When you query, you should order your query by id in ascending order. Not sure which database you are using but I would do:
SELECT * FROM MY_DATABASE WHERE IS_PROCESSED = 'N' ORDER BY ID ASC;
That takes the load of sorting it off of your application and onto your database. Then your query returns unprocessed records with the lowest id's on top. Then just sequentially work through them in order.
I have a table called friendgraph(friend_id, friend_follower_id) and I want to calculate 6-degrees of separation for a given friend and a given degree.
The table looks like this:
friend_id, friend_follower_id
0,1
0,9
1,47
1,12
2,41
2,66
2,75
3,65
3,21
3,4
3,94
4,64
4,32
How do I go and built a query where given friend_id_a, and order_k, find the users who are k degree apart from friend_id_a?
This is how my initial query file looks like:
create or replace function degree6
(friend_id_a in integer, order_k in integer)
return sys_refcursor as crs sys_refcursor;
I am looking for any kind of help or resources that will get me started and eventually arrive at the output.
UPDATE:
The output would be a list of other friends k degrees apart from friend_id_a.
Define order-k follower B of A such that B is not A, and:
1. if k = 0, then A is the only order-0 follower of A.
2. if k = 1, then followers of A are order-1 followers of A.
3. if k > 1; then for i = 0 to k-1, B is not order-i follower of A; and B is a follower
of a order-(k-1) follower of A
Thanks.
You can build a hierarchical query and filter by level and friend_id. For example to get all friends of user 0 at level 3:
SELECT friend_id, friend_follower_id, level
FROM friends
WHERE LEVEL = 3
CONNECT BY PRIOR friend_follower_id = friend_id
START WITH friend_id = 0
On Oracle 11gR2 or later we can use the recursive subquery-factoring syntax to do this.
with friends (id, follower, lvl) as
( select friend_id, friend_follower_id, 1
from friendgraph
where friend_id = 0
union all
select fg.friend_id, fg.friend_follower_id, f.lvl + 1
from friendgraph fg
join
friends f
on (fg.friend_id = f.follower)
where f.lvl + 1 <= 3
)
select *
from friends
/
Here's one way of implementing this in a function with a Ref Cursor:
create or replace function degree6
(friend_id_a in integer
, order_k in integer)
return sys_refcursor
is
return_value sys_refcursor;
begin
open return_value for
with friends (id, follower, lvl) as
( select friend_id, friend_follower_id, 1
from friendgraph
where friend_id = friend_id_a
union all
select fg.friend_id, fg.friend_follower_id, f.lvl + 1
from friendgraph fg
join
friends f
on (fg.friend_id = f.follower)
where f.lvl + 1 <= order_k
)
select *
from friends;
return return_value;
end degree6;
/
Using it in SQL*Plus:
SQL> var rc refcursor
SQL> exec :rc := degree6(0,3)
PL/SQL procedure successfully completed.
SQL> print rc
ID FOLLOWER LVL
---------- ---------- ----------
0 1 1
0 9 1
1 12 2
1 47 2
SQL>