JDBC, spring: How to bulk update using JdbcTemplate - mysql

I'm trying to update one Column data with the value. CARD Table Example likes below.
| id | column_for_update |
| 1 | 10 |
| 2 | 11 |
| 3 | 12 |
| 4 | 13 |
| 5 | 14 |
...
Using jdbcTemplate(or other possible templates), I wanted to update column_for_update to 1000 * n(n = 1, 2, 3 ..), and result will be like ['10, 11, 12 ...'] -> ['1000, 2000, 3000'].
It is possible importing all objects into the application level and update them, but importing a large number of objects causes outOfMemory exceptions. How can I update this columns efficiently?

You can try changing your query to use a UPDATE/SELECT to multiply your id column by 1000:
UPDATE card a
INNER JOIN card b ON a.id = b.id
SET a.column_for_update = (b.id * 1000)
id
column for update
1
1000
2
2000
3
3000
4
4000
5
5000
See Fiddle.

Related

Merge two tables together and overwrite exisiting values with SQL

I try to merge two tables together and want to get a single table with SQL. My main problem is to overwrite existing values, because in the 2nd table (deltaTable) are some new revision rows, that have the same ID as in the first table (rootTable).
Example:
1) rootTable
ID | REV | NAME
1 | 0 | Part 1
2 | 0 | Part 2
3 | 0 | Part 3
4 | 0 | Part 4
5 | 0 | Part 5
2) deltaTable
ID | REV | NAME
2 | 1 | Part 2
4 | 2 | New Part 4
I want to have the following result:
ID | REV | NAME
1 | 0 | Part 1
2 | 1 | Part 2
3 | 0 | Part 3
4 | 2 | New Part 4
5 | 0 | Part 5
Can anyone help me or give me an hint how to manage the SQL code?
If I understand your question correctly, you could use an UPDATE query:
update
rootTable r inner join deltaTable d
on r.id = d.id
set
r.REV = d.REV,
r.NAME = d.NAME
Please see it working here.
As Hogan suggested, we could add something like where d.rev>r.rev since it should help giving better performances.
An alternative query, if you defined ID as a primary key, is:
insert into rootTable (ID, REV, NAME)
select * from deltaTable
on duplicate key update
REV=values(REV), NAME=values(NAME);
(this will update existing records, and add new ones).
Please see it here.

MySQL - Get values from previous rows

I am trying to reconstruct data that has a tree structure.
Example - Country / City:
1) USA
1.1) New York
1.2) Chicago
2) France
2.1) Paris
2.2) Lyon
3) China
In my database it looks like this:
| Element | Level | Row |
|:--------:|:-----:|:---:|
| USA | 1 | 1 |
| New York | 2 | 2 |
| Chicago | 2 | 3 |
| France | 1 | 4 |
| Paris | 2 | 5 |
| Lyon | 2 | 6 |
| China | 1 | 7 |
Based on the sequence (row) of my entries I can reconstruct the tree structure. For each row I look for the nearest previous row that has Level-1.
max(pre.Row) / pre.Row < cur.Row / pre.Level = cur.Level-1
Following code is working and it returns the right results. My problem is that the table is 7 million rows large and therefore it takes a lot of time. It is like comparing 7 million times 7 million rows...
SELECT cur.`Row`, (
SELECT max(pre.`Row`)
FROM `abc`.`def` AS pre
WHERE pre.`Row` < cur.`Row`
AND pre.`Level`=cur.`Level`-1
) AS prev_row
FROM `abc`.`def` AS cur
;
Is there a faster way to implement this?
Maybe with loops or user variables? I could imagine that you actually start from the current row and then test if the previous row meets the conditions otherwise look for the next previous row and so on. This will reduce the opertions to 7 million times ~5. I never worked with loops so I have no clue if this is possible in SQL. Any ideas?
here's my try with 3 levels you can add levels if you have more, not sure why it's returning weird values that look like encoded values but CAST() AS unSIGNED gets you prev_row just as your query.
SELECT Row,
CAST(ELT(level-1,#level_1,#level_2,#level_3) as UNSIGNED) as prev_row,
#level_1 := IF(`level` = 1, row, #level_1),
#level_2 := IF(`level` = 2, row, #level_2),
#level_3 := IF(`level` = 3, row, #level_3)
FROM `def`
ORDER BY Row ASC
http://sqlfiddle.com/#!9/719b2/22

mysql update with subquery 2 level deep

Thanks for taking a look at this question. I'm kind of lost and hope someone can help me. Below is a update query i would like to run.
This query now returns an error:
1054 - Unknown column 'spi.et_cross_rank' in 'where clause'
Some background:
from table: tmp_ranking_tbl
I would like to get the nth(spi.et_return_rank) record
for a group with value x (spi.et_cross_rank)
SET #rownum=0;
UPDATE STRToer_Poule_indeling spi
SET spi.team_id = (SELECT R.team_poule_id
FROM (SELECT #rownum:=#rownum+1 AS rownum, trt.team_poule_id
FROM tmp_ranking_tbl trt
WHERE trt.overal_rank = spi.et_cross_rank
ORDER BY trt.punten DESC, (trt.goals_voor - trt.goals_tegen) DESC, trt.goals_voor DESC) R
WHERE R.rownum = spi.et_return_rank)
WHERE spi.et_ronde = v_et_ronde
AND spi.poule_id IN (SELECT row_id FROM STRToer_Poules WHERE toernooi_onderdeel_id=v_onderdeel_id) ;
Data in tmp_ranking_tbl looks like:
team_poule_id | punten | goals_voor | goals_tegen | overal_rank
65 | 6 | 10 | 10 | 2
69 | 6 | 9 | 10 | 2
75 | 7 | 11 | 4 | 2
84 | 6 | 6 | 8 | 2
112 | 5 | 7 | 7 | 2
Thanks in advance for the help!
Update after question in comment about the goal, i'll try to keep it short. :-)
This query is used on a website to keep scores of a tournament. Sometimes you have an odd number of teams going to the next round. At that point I want to select the best number 3(spi.et_cross_rank) team across poules. This is setting saved in the STRToer_Poule_indeling with what rank per poule and the 1st, 2nd or nth team(spi.et_return_rank). The table tmp_ranking_tbl is filled with all rank 3 teams across the poules. When this if filled I would like the 1st or 2nd, depedining on the setting in STRToer_Poule_indeling, record to return.
Subset of structure the STRToer_Poule_indeling table
row_id | team_id | et_ronde | et_cross_rank | et_return_rank
1 | null | 1 | 3 | 1
Just check if you have a column named et_cross_rank on your table STRToer_Poule_indeling
The problem seems to be that SQL can't find that column on your table.
Hope it helps.

Self join and recursive selection in a table

Assuming a table as below
| ID | NAME | ROLE | MGRID |
---------------------------
| 1 | ONE | 5 | 5 |
| 2 | TWO | 5 | 5 |
| 3 | THREE | 5 | 6 |
| 4 | FOUR | 5 | 6 |
| 5 | FIVE | 15 | 7 |
| 6 | SIX | 25 | 8 |
| 7 | SEVEN | 25 | 7 |
| 8 | EIGHT | 5 | 8 |
How do I get a list of all employees reporting to an employee, including the ones who are in subsequent reporting levels below?
I mean, given emp id 5, I should get [1, 2] and given 7, I should get [1, 2, 5, 7]. How do I get this done?
Will self joins be of help here? Need to brush up my knowledge on joins now.
SELECT id
FROM emp
START WITH id = 7
CONNECT BY NOCYCLE mgrid = PRIOR id
SQLFIDDLE LINK
Here is a SQL statement using Oracle.
select id, name, role, mgrID
from employees
start with id = 7
connect by NoCycle prior id = mgrid;
Please note that the manager for employee 7 is the employee 7 - they are their own manager. This will cause an error - "Connect By loop in user data'. By using the NoCycle keyword you can tell Oracle to detect this and avoid the error.
Does this solve your issue?
I know this isn't exactly what you were asking, but if you are willing to choose a finite number of level's to recurse it isn't too bad to write.
SELECT table_2.id
FROM table LEFT JOIN
(table AS table_1 LEFT JOIN table AS table_2 ON table_1.id = table_2.MgrID)
ON table.id = table_1.MgrID
WHERE (((table.id)=7));
ETC.

Is there a query in MySQL that would allow variable group numbers and limits akin to this

I've checked out a few of the stackoverflow questions and there are similar questions, but didn't quite put my fingers on this one.
If you have a table like this:
uid cat_uid itm_uid
1 1 4
2 1 5
3 2 6
4 2 7
5 3 8
6 3 9
where the uid column in auto_incremented and the cat_uid references a
category of relevance to filter on and the itm_uid values are the one
we're seeking
I would like to get a result set that contains the following sample results:
array (
0 => array (1 => array(4,5)),
1 => array (2 => array(6,7)),
2 => array (3 => array(8,9))
)
An example issue is - select 2 records from each category (however many categories there may be) and make sure they are the last 2 entries by uid in those categories.
I'm not sure how to structure the question to allow an answer, and any hints on a method for the solution would be welcome!
EDIT:
This wasn't a very clear question, so let me extend the scenario to something more tangible.
I have a set of records being entered into categories and I would like to select, with as few queries as possible, the latest 2 records entered per category, so that when I list out the contents of those categories, I will have at least 2 records per category (assuming that there are 2 or more already in the database). A similar query was in place that selected the last 100 records and filtered them into categories, but for small numbers of categories with some being updated faster than others can lead to having the top 100 not consisting of members from every category, so to try to resolve that, I was looking for a way to select 2 records from each category (or N-records assuming it's the same per-category) and for those 2 records to be the last entered. A date field is available to sort on, but the itm_uid itself could be used to indicate inserted order.
SELECT cat_uid, itm_uid,
IF( #cat = cat_uid, #cat_row := #cat_row + 1, #cat_row := 0 ) AS cat_row,
#cat := cat_uid
FROM my_table
JOIN (SELECT #cat_row := 0, #cat := 0) AS init
HAVING cat_row < 2
ORDER BY cat_uid, uid DESC
You will have two extra columns in the results, just ignore them.
This is the logic:
We sort the table by cat_uid, uid descending, then we start from the top and give each row a "row number" (cat_row) we reset this row number to zero whenever cat_uid changes:
---------------------------------------
| uid | cat_uid | itm_uid | cat_row |
| 45 | 4 | 34 | 0 |
| 33 | 4 | 54 | 1 |
| 31 | 4 | 12 | 2 |
| 12 | 4 | 51 | 3 |
| 56 | 6 | 11 | 0 |
| 20 | 6 | 64 | 1 |
| 16 | 6 | 76 | 2 |
| ... | ... | ... | ... |
---------------------------------------
now if we keep only the rows that have cat_row < 2 we get the results we want:
---------------------------------------
| uid | cat_uid | itm_uid | cat_row |
| 45 | 4 | 34 | 0 |
| 33 | 4 | 54 | 1 |
| 56 | 6 | 11 | 0 |
| 20 | 6 | 64 | 1 |
| ... | ... | ... | ... |
---------------------------------------
This is called an adjacent tree model or a parent-child tree model. It's one of the simplier tree model where there is only 1 pointer or 1 leaf. You would solve your query with a recursion or using a Self Join. Sadly MySQL doesn't support recursive queries, maybe it's working with prepared statements. I want to suggest you an Self Join. With a Self Join you can get all the rows from the right side and the left side with a special condition.
select t1.cat_uid, t2.cat_uid, t1.itm_uid, t2.itm_uid From t1 Inner Join t2 On t1.cat_uid = t2.cat_uid