UPDATE with SELECT statement but re-select on each update - mysql

I'm trying to update multiple rows in MySQL by selecting the highest number and adding 1 to it to generate the next one.
UPDATE orders SET delivery_number = (
SELECT new_number FROM (
SELECT (
MAX(delivery_number) + 1
) AS new_number FROM order_invoice
) AS result
) WHERE delivery_number = 0 AND invoice_number != 0;
The query above only seems to SELECT once, then use the same number for each update.
How can I force it to scan the table again for the highest number on each update?

update orders, (select #n:=max(delivery_number) from order_invoice) n
set delivery_number = #n:=#n+1
where delivery_number = 0 and invoice_number != 0;

Related

Update int column values mysql

I want to update an int column values where I want to set the value of the int column to 1 for the latest inserted record and increment it by 1 for all the preceding records until the record with Primary Id = 1 is reached. I've some 1400 records so what I want is that 1400 record should get 1 for that int column and the 1399 should get 2 and so on until all records are finished. How should the update query be written so that can be achieved. Thanks
Note this is going to be one time operation.
If you are running MySQL 8.0, you can use row_number() for this. Assuming that you have a unique, ordering column called id, and that you want to update column new_id:
update mytable t
inner join (select id, row_number() over(order by id desc) new_id from mytable) x
on t.id = x.id
set t.new_id = x.new_id
In earlier versions, one option is to emulate the window function with a user variable:
update mytable t
inner join (
select t.id, #new_id := #new_id + 1 new_id
from (select id from mytable order by id desc) t
cross join (select #new_id := 0) x
) x on t.id = x.id
set t.new_id = x.new_id

SQL Update for Selected rows

I have this SQL Code:
SELECT * FROM `clients_branches`
WHERE NULLIF(clients_branches.invoice_email, '') IS NULL
GROUP BY client_code
HAVING COUNT(*) = 1
It returns all rows which appears only once in the database, also it returns only the ones with no email set. Now I need to apply UPDATE function to all of this select statement. How could I do it? I need to set clients_branches.invoice_send to 0 for all these rows.
I can't seem to use HAVING COUNT on UPDATE statement like this:
UPDATE `clients_branches`
SET clients_branches.invoice_send = 0
WHERE NULLIF(clients_branches.invoice_email, '') IS NULL
HAVING COUNT(*) = 1
Without HAVING COUNT I will change all of the rows which repeats at least once in this table. And I need to change only the ones with count = 1.
You could use a join for allow the use of the table for update and the result of your query
update `clients_branches`
JOIN
(
select client_code, count(*)
FROM `clients_branches`
WHERE NULLIF(clients_branches.invoice_email, '') IS NULL
group by client_code
HAVING COUNT(*) = 1
) t on t.client_code = `clients_branches`.client_code
set clients_branches.invoice_send = 0
;

update row if count(*) > n

my DB has this structure:
ID | text | time | valid
This is my current code. I'm trying to find a way to do this as one query.
rows = select * from table where ID=x order by time desc;
n=0;
foreach rows{
if(n > 3){
update table set valid = -1 where rows[n];
}
n++
}
I'm checking how many rows exist for a given ID. Then I need to set valid=-1 for all rows where n >3;
Is there a way to do this with one query?
You can use a subquery in the WHERE clause, like this:
UPDATE table
SET valid=-1
WHERE (
SELECT COUNT(*)
FROM table tt
WHERE tt.time > table.time
AND tt.ID = table.ID
) > 3
The subquery counts the rows with the same ID and a later time. This count will be three or less for the three latest rows; the remaining ones would have a greater count, so their valid field would be updated.
Assuming that (id,time) has a UNIQUE constraint, i.e. no two rows have the same id and same time:
UPDATE
tableX AS tu
JOIN
( SELECT time
FROM tableX
WHERE id = #X -- the given ID
ORDER BY time DESC
LIMIT 1 OFFSET 2
) AS t3
ON tu.id = #X -- given ID again
AND tu.time < t3.time
SET
tu.valid = -1 ;
update table
set valid = -1
where id in (select id
from table
where id = GIVEN_ID
group by id
having count(1) >3)
Update: I really like dasblinkenlight's solution because is very neat, but I wanted to try also to do it in my way, a quite verbose one:
update Table1
set valid = -1
where (id, time) in (select id,
time
from (select id,time
from table1
where id in (select id
from table1
group by id
having count(1) >3)
-- and id = GIVEN_ID
order by time
limit 3, 10000000)
t);
Also in SQLFiddle
to do it for all ids, or only for one if you set a where in the a subquery
UPDATE TABLE
LEFT JOIN (
SELECT *
FROM (
SELECT #rn:=if(#prv=id, #rn+1, 1) AS rId,
#prv:=id AS id,
TABLE.*
FROM TABLE
JOIN ( SELECT #prv:=0, #rn:=0 ) tmp
ORDER BY id, TIMESTAMP
) a
WHERE rid > 3
) ordered ON ordered.id = TABLE.id
AND ordered.TIMESTAMP = TABLE.TIMESTAMP
AND ordered.text = TIMESTAMP.text
SET VALID = -1
WHERE rid IS NOT NULL

Get sequential rows that have same column values is SQL Server 2008

I need to know the sequential rows which have some same values
I need the rows which have prsstatus value of 0 and then next row is 1
Another method, change MyTable to whatever your table is and change the ORDER BY clause to whatever columns you want to sort by.
;WITH MyTableSort AS (
SELECT TblID, EmpID, PrsDay, PrsTime, PrsStatus, ROW_NUMBER() OVER (ORDER BY MyTable.TblID) [Row] FROM MyTable
)
SELECT * FROM MyTableSort AS MyTableSortA
WHERE (MyTableSortA.PrsStatus = 0 AND EXISTS (SELECT 1 FROM MyTableSort WHERE MyTableSort.[Row] = MyTableSortA.[row]+1 AND MyTableSort.PrsStatus = 1))
Assuming you mean "next" row in terms of dense values on TblID:
select YTN.*
from YourTableName as YTN inner join
YourTableName as NR on NR.TblID = YTN.TblId + 1 and
NR.PrsStatus = 1 and YTN.PrsStatus = 0

Find the first record which caused SUM to become 0

I am using MySQL 5.5 to store a table like:
sequence category value
1 A 100
2 A 200
3 A -300 # sum becomes 0
4 B 200
5 B 500
For each category, I would like to find the first record (ordered by sequence) which caused sum(value) of the category to drop below 0.
My current solution is (SQL function pseudo code):
create function find_low_value(in_category) returns int
begin
declare cursor select sequence, value from table where category = in_category;
declare sum int default 0;
open and fetch cursor;
set sum = sum + value;
if sum <= 0 then
return sequence;
end if;
end
But it is not efficient. Is there a better/ simpler solution?
Thanks.
I don't know if this counts as "better/ simpler", but you can write it as a regular SQL query:
SELECT MIN(sequence)
FROM ( SELECT t1.sequence
FROM table_name t1
JOIN table_name t2
ON t2.category = t1.category
AND t2.sequence <= t1.sequence
WHERE t1.category = ...
GROUP
BY t1.sequence
HAVING SUM(t2.value) <= 0
)
;
select min(id),category,sum(value) as total_sum from test group by category
having total_sum<=0