Updating batch of rows depending on last row of previous batch - sql-server-2008

I have following data -
create table #Test(
Id int
,JobNo int
)
insert into #Test
values
(1,100) ,(2,100)
,(3,101),(4,104)
,(5,105),(6,106)
My requirement is that I need to update batch of rows sequentially. Say batch size here is 2, then for rows between Id 3 to 4, I need to take the JobId value of 100 from first batch and increment it to 1. Likewise for rows between Id 5-6, I need to update JobId as 102.
Expected Output is -
Id,JobId
1,100
2,100
3,101
4,101
5,102
6,102
I am able to achieve this using while loop and counter but am just wondering if it can be done via partitioning and self-joins. I am not able to get the right partitioning criteria to divide them into equal batches. Even if I partition I don't know how to proceed with sequentially add up the values. A recursive CTE perhaps? Just pondering.

Try this:
UPDATE t_curr
SET JobNo = ISNULL(t_prev.JobNo + ((t_curr.Id - 1) / #batchSize), t_curr.JobNo)
FROM #Test t_curr
JOIN #Test t_prev ON t_prev.Id = t_curr.Id - #batchSize
Let me know if it is not something you need.

Related

MySQL/SQLite insert same random # to multiple rows

MySQL/SQLite
I want to insert a randomly generated number (of 9 positions) into multiple rows BUT they need to be the same for all rows matched in the query.
update products set tag_seed=( SELECT ABS(RANDOM() % 999999999) ) where [...];
Partialy works... Each row will have a different random number. I need them to be same.
This is logical since you will generate a new random for every update query. The easiest solution is to generate a random integer, store it in a local variable and use that variable in your queries:
SET #rand := (SELECT ABS(RAND() * 1000000000));
update products set tag_seed=#rand where [...];

MySQL INSERT IF (custom if statements)

First, here's the concise summary of the question:
Is it possible to run an INSERT statement conditionally?
Something akin to this:
IF(expression) INSERT...
Now, I know I can do this with a stored procedure.
My question is: can I do this in my query?
Now, why would I want to do that?
Let's assume we have the following 2 tables:
products: id, qty_on_hand
orders: id, product_id, qty
Now, let's say an order for 20 Voodoo Dolls (product id 2) comes in.
We first check if there's enough Quantity On Hand:
SELECT IF(
( SELECT SUM(qty) FROM orders WHERE product_id = 2 ) + 20
<=
( SELECT qty_on_hand FROM products WHERE id = 2)
, 'true', 'false');
Then, if it evaluates to true, we run an INSERT query.
So far so good.
However, there's a problem with concurrency.
If 2 orders come in at the exact same time, they might both read the quantity-on-hand before any one of them has entered the order.
They'll then both place the order, thus exceeding the qty_on_hand.
So, back to the root of the question:
Is it possible to run an INSERT statement conditionally, so that we can combine both these queries into one?
I searched around a lot, and the only type of conditional INSERT statement that I could find was ON DUPLICATE KEY, which obviously does not apply here.
INSERT INTO TABLE
SELECT value_for_column1, value_for_column2, ...
FROM wherever
WHERE your_special_condition
If no rows are returned from the select (because your special condition is false) no insert happens.
Using your schema from question (assuming your id column is auto_increment):
insert into orders (product_id, qty)
select 2, 20
where (SELECT qty_on_hand FROM products WHERE id = 2) > 20;
This will insert no rows if there's not enough stock on hand, otherwise it will create the order row.
Nice idea btw!
Try:
INSERT INTO orders(product_id, qty)
SELECT 2, 20 FROM products WHERE id = 2 AND qty_on_hand >= 20
If a product with id equal to 2 exists and the qty_on_hand is greater or equal to 20 for this product, then an insert will occur with the values product_id = 2, and qty = 20. Otherwise, no insert will occur.
Note: If your product ids are note unique, you might want to add a LIMIT clause at the end of the SELECT statement.
Not sure about concurrency, you'll need to read up on locking in mysql, but this will let you be sure that you only take 20 items if 20 items are available:
update products
set qty_on_hand = qty_on_hand - 20
where qty_on_hand >= 20
and id=2
You can then check how many rows were affected. If none were affected, you did not have enough stock. If 1 row was affected, you have effectively consumed the stock.
You're probably solving the problem the wrong way.
If you're afraid two read-operations will occur at the same time and thus one will work with stale data, the solution is to use locks or transactions.
Have the query do this:
lock table for read
read table
update table
release lock
I wanted to insert into a table using values so I found this solution to insert the values using the IF condition
DELIMITER $$
CREATE PROCEDURE insertIssue()
BEGIN
IF (1 NOT IN (select I.issue_number from issue as I where I.series_id = 1)) THEN
INSERT IGNORE INTO issue ( issue_number, month_published, year_published, series_id, mcs_issue_id) VALUES (1, 1, 1990, 1, 1);
END IF;
END$$
DELIMITER ;
If you later on want to call the procedure it's as simple as
CALL insertIssue()
You can find more information about PROCEDURES and if conditions in this site

MySQL Problem with inserting a row with certain conditions

I have a problem inserting a row in a MySQL table when the table is completely empty.
I use this query :
INSERT IGNORE INTO test (id, amount)
SELECT 6, 50 FROM test WHERE NOT EXISTS
(SELECT 1 FROM test WHERE amount >= 50 AND id = 6) LIMIT 1
It works fine when there is at least one entry in the table, whatever the data in the columns are. It doesn't work if the table is completely empty.
Basically, I want to insert a row if a row with the same ID and an amount equals or higher doesn't exists.
I tried with a COUNT also, still the same problem. Is there another way of doing this?
I think the only thing wrong with this is on line two, remove FROM test.. You can't select 6, 50 from test.. 6 and 50 are not columns in test, and test has no records. Try it like this:
INSERT IGNORE INTO test (id, amount)
SELECT * from (select 6, 50) as a
WHERE NOT EXISTS (SELECT 1 FROM test
WHERE amount >= 50 AND id = 6)

Is it really no solution to update multiple records in MySQL?

I want to do all these update in one statement.
update table set ts=ts_1 where id=1
update table set ts=ts_2 where id=2
...
update table set ts=ts_n where id=n
Is it?
Use this:
UPDATE `table` SET `ts`=CONCAT('ts_', `id`);
Yes you can but that would require a table (if only virtual/temporary), where you's store the id + ts value pairs, and then run an UPDATE with the FROM syntax.
Assuming tmpList is a table with an id and a ts_value column, filled with the pairs of id value, ts value you wish to apply.
UPDATE table, tmpList
SET table.ts = tmpList.ts_value
WHERE table.id = tmpList.id
-- AND table.id IN (1, 2, 3, .. n)
-- above "AND" is only needed if somehow you wish to limit it, i.e
-- if tmpTbl has more idsthan you wish to update
A possibly table-less (but similar) approach would involve a CASE statement, as in:
UPDATE table
SET ts = CASE id
WHEN 1 THEN 'ts_1'
WHEN 2 THEN 'ts_2'
-- ..
WHEN n THEN 'ts_n'
END
WHERE id in (1, 2, ... n) -- here this is necessary I believe
Well, without knowing what data, I'm not sure whether the answer is yes or no.
It certainly is possible to update multiple rows at once:
update table table1 set field1='value' where field2='bar'
This will update every row in table2 whose field2 value is 'bar'.
update table1 set field1='value' where field2 in (1, 2, 3, 4)
This will update every row in the table whose field2 value is 1, 2, 3 or 4.
update table1 set field1='value' where field2 > 5
This will update every row in the table whose field2 value is greater than 5.
update table1 set field1=concat('value', id)
This will update every row in the table, setting the field1 value to 'value' plus the value of that row's id field.
You could do it with a case statement, but it wouldn't be pretty:
UPDATE table
SET ts = CASE id WHEN 1 THEN ts_1 WHEN 2 THEN ts_2 ... WHEN n THEN ts_n END
I think that you should expand the context of the problem. Why do you want/need all the updates to be done in one statement? What benefit does that give you? Perhaps there's another way to get that benefit.
Presumably you are interacting with sql via some code, so certainly you can simply make sure that the three updates all happen atomically by creating a function that performs all three of the updates.
e.g. pseudocode:
function update_all_three(val){
// all the updates in one function
}
The difference between a single function update and some kind of update that performs multiple updates at once is probably not a very useful distinction.
generate the statements:
select concat('update table set ts = ts_', id, ' where id = ', id, '; ')
from table
or generate the case conditions, then connect it to your update statement:
select concat('when ', id, ' then ts_', id) from table
You can use INSERT ... ON DUPLICATE KEY UPDATE. See this quesion: Multiple Updates in MySQL
ts_1, ts_2, ts_3, etc. are different fields on the same table? There's no way to do that with a single statement.

copy one column from one table to another

I am confused about how to copy a column from one table to another table using where. I wrote SQL query but it says transaction lock time exceeded or query returns more than one row.
using mysql
Basically,
I have:
Table 1: Results
BuildID platform_to_insert
Table 2: build
BuildID correct_platform
update results set results.platform_to_insert
= (select correct_platform from
build where results.BuildID = build.BuildID)
I do not believe you need a sub query.
UPDATE results, build
SET results.platform_to_insert = build.correct_platform
WHERE results.BuildID = build.BuildID
There are two options here:
update your tables to use BuildID as a primary key (to avoid duplicates)
update your subquery to only return one result
UPDATE results SET results.platform_to_insert = (
SELECT correct_platform
FROM build
WHERE results.BuildID=build.BuildID LIMIT 1
);