Update multiple rows from same table in mysql - mysql

Update a single column over multiple rows depending on the data from the same table.
update table1 set status=newtime
from (
select
case
when TIME_FORMAT( TIMEDIFF( ADDTIME( time_val, '120:00:00' ), NOW() ), '%Hh %im %ss')<0 then '4'
else '0'
end as newtime,
id as new_id
FROM table1
where id2='2'
and status='0'
)
where id=new_id
This is my query. Thanks in advance.
Edit:
This is an alternate query to achieve this. But it also gives me an error
update table1 set status=
(select
case when timeleft<0 then '4' else '0' end as something,
new_id
from
(
select
TIME_FORMAT( TIMEDIFF( ADDTIME( time_val, '120:00:00' ), NOW() ), '%Hh %im %ss') as newtime,
id as new_id
FROM
table1
where id2='2' and
status='0'
)
}
where id=new_id
"#1248 - Every derived table must have its own alias".
I cannot use alias as I am fetching two columns from the query. Any help would be great.

UPDATE statements have no FROM clause in MySQL syntax. However, you can JOIN table against the subquery.
UPDATE
table1 t1
JOIN (
select
case
when TIME_FORMAT( TIMEDIFF( ADDTIME( time_val, '120:00:00' ), NOW() ), '%Hh %im %ss')<0 then '4'
else '0'
end as newtime,
id as new_id
FROM table1
WHERE id2='2' AND status='0'
) tsub ON t1.id = tsub.new_id
SET status = tsub.newtime

It looks to me like you don't need to do any subquerying or joining at all. This should do what you want:
UPDATE table1
SET status = CASE WHEN TIME_FORMAT(TIMEDIFF(ADDTIME(time_val, '120:00:00'), NOW()), '%Hh %im %ss') < 0 THEN '4' ELSE '0' END
WHERE id2 = '2' AND status = '0'
In the query you wrote, your subquery will get back the new time_val and the id number of the row to update, for any rows that match the criteria id2 = '2' AND status = '0'. You will then update all those rows (that matched the above criteria) and set the status to the new time_val.
Instead of selecting them first, cut out the middle man and just update all rows that match that criteria with the new value. Your query will be faster and more straightforward.

Besides the simplified version (provided by #Travesty3), it seems you are using a whole bunch of date and time functions to test for a simple thing:
UPDATE table1
SET status = '4'
WHERE id2 = '2'
AND status = '0'
AND time_val < NOW() - INTERVAL 120 HOUR

We can update table with multiple row by same table or two different table in this manner, just posting a snippet of mysql code from my procedure
Update documentcolumns as tb1, documentcolumns as tb2 set tb1.documentColumnPos = tb2.documentColumnPos Where tb1.userID = user_id and tb2.userID is NULL and tb1.columnNameDefID= tb2.columnNameDefID and tb1.tabtype = tab_type and tb2.tabtype = tab_type;,

Related

select sum until certain amount and then update certain fields based on condition

I have a query that changes the status of some fields and rate of another field.
fiddle expample
CREATE TABLE mytable(
item_id INTEGER NOT NULL PRIMARY KEY
,rate INTEGER NOT NULL
,status VARCHAR(6) NOT NULL
);
INSERT INTO mytable(item_id,rate,status) VALUES (1,12,'credit');
INSERT INTO mytable(item_id,rate,status) VALUES (2,10,'credit');
INSERT INTO mytable(item_id,rate,status) VALUES (3,10,'credit');
INSERT INTO mytable(item_id,rate,status) VALUES (4,20,'cash');
INSERT INTO mytable(item_id,rate,status) VALUES (5,55,'credit');
select item_id, 'cash' as status,
case when sum_rate >= 23 then sum_rate - 23 else rate end as rate
from (
select t.*, sum(rate) over(order by item_id) sum_rate
from mytable t
where status = 'credit'
) t
where sum_rate - rate < 23;
update mytable t
inner join (
select item_id, sum(rate) over(order by item_id) sum_rate
from mytable t
where status = 'credit'
) t1 on t1.item_id = t.item_id
set
t.status = 'cash',
t.rate = case when t1.sum_rate >= 23 then t1.sum_rate - 23 else t.rate end
where t1.sum_rate - t.rate < 23
The logic checks the sum of all rows until a value of 23 is reached and changes the status of those rows to cash, in the example since the total of rate in top 3 rows is greater than 23, the third row is updated with the balance after adding the first two rows. I want the third row status to remain the same and only the rate to be updated.
The problem the above code is that it updates all the status of all rows having sum of rate 23.
The original question for reference
Ok I was able to get it done with the following addition to the query so posting it in case it may help anyone with a similar requirement.
t.status = case when t1.sum_rate >= 23 then 'credit' else 'cash' end

How to write the a new select query with backward compatibility after adding a new column to a MySQL database

I have a MySQL table running for 4 months and I have a select statement in that table, like below.
SELECT
CONCAT(
YEAR(FROM_UNIXTIME(creation_time)),
'-',
IF(
MONTH(FROM_UNIXTIME(creation_time)) < 10,
CONCAT('0', MONTH(FROM_UNIXTIME(creation_time))),
MONTH(FROM_UNIXTIME(creation_time))
)
) AS Period,
(
COUNT(CASE
WHEN system_name = 'System' THEN 1
ELSE NULL
END)
) AS "Some data",
FROM table_name
GROUP BY
Period
ORDER BY
Period DESC
Lately, I've added a new feature and a column, let's say is_rerun. This value is just added and not exist previously. Now, i would like to write a query with the current statement which checks the system_name and also the is_rerun field and if this field exists and value is 1 then return 1 and if the column not exist or it its value is zero, then return null.
I tried IF EXISTS re_run THEN 1 ELSE NULL, but no luck. I can also insert values for the previous runs but i don't want to do that. Is there any solution. Thanks.
SELECT
CONCAT(
YEAR(FROM_UNIXTIME(creation_time)),
'-',
IF(
MONTH(FROM_UNIXTIME(creation_time)) < 10,
CONCAT('0', MONTH(FROM_UNIXTIME(creation_time))),
MONTH(FROM_UNIXTIME(creation_time))
)
) AS Period,
(
COUNT(CASE
WHEN system_name = 'System' AND IF EXISTS is_rerun THEN 1
ELSE NULL
END)
) AS "Some data",
FROM table_name
GROUP BY
Period
ORDER BY
Period DESC
As a starter: you have a group by query, so you need to put is_rerun in an aggregate function.
Based on your description, I think that something like case(case when is_rerun = 1 then 1 end) should do the work: it returns 1 if any is_rerun in the group is 1, else null.
Or if you can live with 0 instead of null, then you can use a simpler expression: max(is_rerun = 1).
Note that your query could be largely simplified as for the date formating logic and the conditional count. I would phrase it as:
select
date_format(from_unixtime(creation_time),'%Y-%m') period,
sum(system_name = 'System') some_data,
max(is_rerun = 1) is_rerun
from mytable
group by period
order by period desc

MySQL rows with maximum and specific values

I have to write a query to retrieve data from a table, using the selected date and selected category. I have written a query and it does not give correct data as expected. It should query only rows with maximum actiondate, if the action column has the value 'AD'.
INSERT INTO goldstockvaluation SELECT sh.stockid, sh.description, sh.branch, sh.grossweight, sh.pureweight, sh.purity, sh.goldcarat, sh.mcpergram, sh.goldpergram, sh.fixgold, CURDATE( )
FROM stock_history sh
JOIN (
SELECT stockid, branch,ACTION , MAX( actiondate ) AS MaxDateTime
FROM stock_history
GROUP BY stockid,branch,ACTION
)groupedsh ON sh.stockid = groupedsh.stockid
AND sh.actiondate = groupedsh.MaxDateTime
AND sh.branch = groupedsh.branch
AND sh.action = groupedsh.action
AND sh.branch = '8'
AND sh.categoryid = 'G'
AND sh.action = 'AD'
AND sh.actiondate <= '2016-03-28 23:59:59'
This is to query out the rows that have action as 'AD' and have the max(actiondate).
To query with max(action_date), you need to use sub query, e.g.:
select field1, field2
from table
where
sh.action = 'AD'
and sh.actiondate = (
select max(sh.actiondate)
from table
where sh.action = 'AD'
);

Issue with updating a table

I have this table
What I want to do is that Select the attr_id WHERE a DISTINCT name_en-GB appears and then SET that selected attr_id for that name_en-GB
I can do this by writing individual queries but I want to know is there any way I can do this in one query?
You can do
UPDATE table1
SET attr_id = CASE `name_en-GB` WHEN 'Bride Name' THEN 142
WHEN 'Child Grade' THEN 270 END
WHERE `name_en-GB` IN('Bride Name', 'Child Grade')
Here is SQLFiddle demo
you can do this simply with an update query and a select.. however I don't know what is the criteria for the first appearence of an attr_id
assumption - first appearance is by the smallest attr_id
UPDATE table t,
( SELECT MIN(attr_id), `name_en-GB`
FROM table
GROUP BY `name_en-GB`
) t1
SET t.attr_id = t1.attr_id
WHERE t1.`name_en-GB` = t.`name_en-GB`
I have finally done this
UPDATE sc_product_phrase
JOIN (
SELECT
`caption`,
min(design_phrase_id) AS minai,
required
FROM
sc_product_phrase WHERE LENGTH(`options`) < 1
GROUP BY
`caption`
) tt ON sc_product_phrase.`caption` = tt.`caption`
AND sc_product_phrase.required = tt.required
SET design_phrase_id = tt.minai
WHERE
sc_product_phrase.design_phrase_id <> tt.minai
AND LENGTH(
sc_product_phrase.`options`
) < 1

MYSQL Query : How to get values per category?

I have huge table with millions of records that store stock values by timestamp. Structure is as below:
Stock, timestamp, value
goog,1112345,200.4
goog,112346,220.4
Apple,112343,505
Apple,112346,550
I would like to query this table by timestamp. If the timestamp matches,all corresponding stock records should be returned, if there is no record for a stock for that timestamp, the immediate previous one should be returned. In the above ex, if I query by timestamp=1112345 then the query should return 2 records:
goog,1112345,200.4
Apple,112343,505 (immediate previous record)
I have tried several different ways to write this query but no success & Im sure I'm missing something. Can someone help please.
SELECT `Stock`, `timestamp`, `value`
FROM `myTable`
WHERE `timestamp` = 1112345
UNION ALL
SELECT `Stock`, `timestamp`, `value`
FROM `myTable`
WHERE `timestamp` < 1112345
ORDER BY `timestamp` DESC
LIMIT 1
select Stock, timestamp, value from thisTbl where timestamp = ? and fill in timestamp to whatever it should be? Your demo query is available on this fiddle
I don't think there is an easy way to do this query. Here is one approach:
select tprev.*
from (select t.stock,
(select timestamp from t.stock = s.stock and timestamp <= <whatever> order by timestamp limit 1
) as prevtimestamp
from (select distinct stock
from t
) s
) s join
t tprev
on s.prevtimestamp = tprev.prevtimestamp and s.stock = t.stock
This is getting the previous or equal timestamp for the record and then joining it back in. If you have indexes on (stock, timestamp) then this may be rather fast.
Another phrasing of it uses group by:
select tprev.*
from (select t.stock,
max(timestamp) as prevtimestamp
from t
where timestamp <= YOURTIMESTAMP
group by t.stock
) s join
t tprev
on s.prevtimestamp = tprev.prevtimestamp and s.stock = t.stock