Update Multiple Rows in MySQL With Similar Content - mysql

I have an event table. (I didn't create this table)
The fields are id, event_id, start_date, end_date, e_status
The only thing that is not unique is the id. The rest are the same on all rows.
How do I update the status?
I tried:
UPDATE events
SET e_status =
CASE event_id
WHEN 12830 THEN 0
END
WHERE start_date = '2016-06-24 17:30:00'
AND end_date = '2016-06-24 18:00:00'
AND event_id IN (12830)
No updates were changed.

before editing
ID Event Status
1 USA 0
2 UK 0
3 Canada 0
Your simple query would be
update event set status=1
After Editing
ID Event Status
1 USA 1
2 UK 1
3 Canada 1
and if you wants to target specific record just use where clause
update event set status=1 where id=1

If all the data is the same on all rows except for the id column, you shouldn't need any criteria in the WHERE clause. You should be able to just have this:
UPDATE events
SET e_status =
CASE event_id
WHEN 12830 THEN 0
END
And actually, you don't even need the case statement. If all data is the same except for id, then won't all rows have an event_id = 12830? You can just have ==>
UPDATE events
set e_status = 0

Related

Update only the greatest row - Sequential Based Update

I want to write a query to find the LOWEST SEQUENCE for status = REQUEST_PENDING then update it after a certain condition.
For example:
person_name
status
sequence
a
request_progressed
1
b
request_pending
2
c
request_pending
3
If the person named A is done, it's status would change from "request_progressed" to "request_done"; then the next person B will have his status changed to "request_progressed" while the person C stays the same because its sequence is the 3rd.
So I just need to know how do I change the person B status by finding the lowest sequence which has "request_pending" status and THERE IS (SUPPOSED TO BE) ONLY ONE "request_progressed" on the table that is why when it is updated to "request_done" the next "request_pending" need to be updated to "request_progressed".
I tried the following:
update table
set status = 'request_progressed'
where status = 'pending' AND sequence = min(sequence)
In MySQL - you can specify order by and limit in update queries:
update t
set status = 'request_progressed'
where status = 'request_pending'
order by sequence
limit 1
In PostgreSQL - you still need order by and limit but they can only be used inside a subquery:
update t
set status = 'request_progressed'
where (status, sequence) in (
select status, sequence
from t
where status = 'request_pending'
order by sequence
offset 0 rows fetch first 1 row only
)

MySQL - Iterate Through Table

I'm trying to figure out how I can iterate through a table to get a count of how many days an id is not in an Active status.
Say I have the following table:
id
Status
Date
1
Active
1/15/21
1
Inactive
1/13/21
1
Active
1/12/21
1
Inactive
1/9/21
1
Active
1/7/21
2
Active
1/5/21
2
Inactive
1/4/21
2
Inactive
1/2/21
2
Active
1/1/21
The desired output for this example should be:
id
Days Inactive
1
5
2
3
I would like to do a DATEDIFF() when the status changes from Active to Inactive.
I can't just do a SELECT for Status <> Active and do a DATEDIFF() on the MAX and MIN dates in the range because it could go ACTIVE in between that range which would make the count different as seen in the example table.
I think I need a LOOP and/or CURSOR with a variable that gets added to as the count grows for each id, I'm just not sure exactly how to execute that.
Any suggestions or ideas are much appreciated!
Try this:
SELECT id,count(*) as days_inactive FROM table
WHERE status like 'inactive'
GROUP BY id
You can achieve what you want using variables. Just calculate the number of days from the previous date if and only if the id is the same and the current row is an active status, as follows.
select #id :=0, #lastDate := null;
select id, sum(DaysInactive) as DaysInactive
from (
select id, (case when id = #id and status='Active' then datediff(tranDate, #lastDate) else 0 end) as DaysInactive
, #id := id, #lastDate := tranDate
from tablename
order by id, TranDate
) as calc group by id
You can run the inner select separately to confirm that your calculations are correct. It should also work if your table has consecutive 'Inactive' or 'Active' statuses.
Adjust the above for your table and column names.

How to write single statement to retrieve last resume of user watching video if the complete date less than resume date?

I am sure this is pretty simple to do but I can’t do that. My problem :
I Have my sql database with one table keeping users video watching complete status(1) and resume(0). once the user is completed she/he again can watch the video the entry will be resume mode then status again insert 0 to this table.
TableName : sdbi_splms_videohit_track
Id videoid status userid watch_date
1 912230 0 1 2020-08-31 15:54:14
2 912230 1 1 2020-09-09 15:54:14
We need to retrieve only resume videos records the is status =0 and if the is status =1 and watch_date grater resume status=0.
Then First out put
it`s should retrieve 0 record because watch_date date greater that resume status
------ Watching this again on entry increase------------
Id videoid status userid watch_date
1 912230 0 1 2020-08-031 15:54:14
2 912230 1 1 2020-09-09 15:54:14
3 912230 0 1 2020-09-10 15:54:14
Out put the last one if resume again
3 912230 0 1 2020-09-10 15:54:14
My sql current query is below its always return resume record if completed date is greater resume date :
SELECT a.* FROM `sdbi_splms_videohit_track` as a WHERE a.videoid=912230 AND
`a`.`user_view_video` = '0' AND `a`.`user_id` = '1' GROUP BY b.videoid ORDER BY
MAX(a.date_created) DESC
Can you please guide me , if it is possible in single query.
It is difficult to help you with the information you are providing. Maybe you want to consider some changes in you database using at least three tables Like:
users_table
user_id int primary key autoincrement
user_name varchar(xxx)
...........
user_attribute(n)
videos_table
video_id int primary key autoincrement
video_name varchar(xxx)
...........
video_attribute(n)
video_track
id int primary_key autoincrement
video_id int
user_id int
pickup_date date
return_date date default null
This would allow you to select the videos taken from a user and not returned yet (your status 0) like.
SELECT vt.video_id, vt.video_name
FROM videos_track k
INNER JOIN users_table ut using (user_id)
INNER JOIN video_table vt using (video_id)
WHERE ISNULL(k.return_date)
AND ut.user_id = 1
So this query will give you all videos picked up by the user with user:id = 1 and yet not returned. If you need the videos picked up after certain date, you add this condition to the WHERE clause:
AND k.pickup_date <= limit_date
etc.
In other words, You'll be able to query your data with a variety of different questions.
Hope I got the essence of your issue so it may be af any help.

MySQL Event - Update When

I have a table with 7500+ records and every day is inserted about 300 new ones. Each new record can belong to a particular partner where each partner has its own idpartner.
Example of records: (partner A -> idpartner: 1 / partner B -> idpartner: 2 / partnerC -> idpartner: 3)
PartnerA-123
PartnerA-567
PartnerB-999
PartnerB-123
PartnerC-123
What I can not do is an event that runs every 10 minutes which will update the idpartner based on what comes before "-". If it's partnerA-, then idpartner = 1 and so on ...
I'm having to run an update every 10 minutes to keep this updated ... What I do:
update table set idpartner = 1 where name regexp 'partnerA-';
update table set idpartner = 2 where name regexp 'partnerB-';
update table set idpartner = 1 where name regexp 'partnerC-';
How to make an event that update the table every 10 minutes based on names with regexp?

Mysql query to skip rows and check for status changes

I'm building a mysql query but I'm stuck... (I'm logging each minute)
I have 3 tables. Logs, log_field, log_value.
logs -> id, create_time
log_value -> id, log_id,log_field_id,value
log_field -> id, name (one on the entries is status and username)
The values for status can be online,offline and idle...
What I would like to see is from my query is:
When in my logs someone changes from status, I want a row with create_time, username, status.
So for a given user, I want my query to skip rows until a new status appears...
And I need to be able to put a time interval in which status changes are ignored.
Can someone please help ?
Although you have nothing to differentiate an actual "User" (such as by user ID) listed in your post, and what happens if you have two "John Smith" names.
First, an introduction to MySQL #variables. You can think of them as an inline program running while the query is processing rows. You create variables, then change them as each row gets processed, IN THE SAME order as the := assignment in the field selection occurs which is critical. I'll cover that shortly.
Fist an initial premise. You have a field value table of all possible fields that can/do get logged. Of which, two of them exist... one is for the user's name, another for the status you are looking a log changed. I don't know what those internal "ID" numbers are, but they would have to be fixed values per your existing table. In my scenario, I am assuming that field ID = 1 is for the User's Name, and field ID 2 = status column... Otherwise, you would need two more joins to get the field table just to confirm which field was the one you wanted. Obviously my "ID" field values will not match your production tables, so please change those accordingly.
Here's the query...
select FinalAlias.*
from (
select
PQ.*,
if( #lastUser = PQ.LogUser, 1, 0 ) as SameUser,
#lastTime := if( #lastUser = PQ.LogUser, #lastTime, #ignoreTime ) as lastChange,
if( PQ.create_time > #lastTime + interval 20 minute, 1, 0 ) as BeyondInterval,
#lastTime := PQ.create_time as chgTime,
#lastUser := PQ.LogUser as chgUser
from
( select
ByStatus.id,
l.create_time,
ByStatus.Value LogStatus,
ByUser.Value LogUser
from
log_value as ByStatus
join logs l
on ByStatus.log_id = l.id
join log_value as ByUser
on ByStatus.log_id = ByUser.log_id
AND ByUser.log_field_id = 1
where
ByStatus.log_field_id = 2
order by
ByUser.Value,
l.create_time ) PQ,
( select #lastUser := '',
#lastTime := now(),
#ignoreTime := now() ) sqlvars
) FinalAlias
where
SameUser = 1
and BeyondInterval = 1
Now, what's going on. The inner-most query (result alias PQ representing "PreQuery") is just asking for all log values where the field_id = 2 (status column) exists. From that log entry, go to the log table for it's creation time... while we're at it, join AGAIN to the log value table on the same log ID, but this time also look for field_id = 1 so we can get the user name.
Once that is done, get the log ID, Creation time, Status Value and Who it was for all pre-sorted on a per-user basis and sequentially time oriented. This is the critical step. The data must be pre-organized by user/time to compare the "last" time for a given user to the "next" time their log status changed.
Now, the MySQL #variables. Join the prequery to another select of #variables which is given an "sqlvars" query alias. This will pre-initialize the variables fo #lastUser, #lastTime and #ignoreTime. Now, look at what I'm doing in the field list via section
if( #lastUser = PQ.LogUser, 1, 0 ) as SameUser,
#lastTime := if( #lastUser = PQ.LogUser, #lastTime, #ignoreTime ) as lastChange,
if( PQ.create_time > #lastTime + interval 20 minute, 1, 0 ) as BeyondInterval,
#lastTime := PQ.create_time as chgTime,
#lastUser := PQ.LogUser as chgUser
This is like doing the following pseudo code in a loop for every record (which is already sequentially ordered by same person and their respective log time
FOR EACH ROW IN RESULT SET
Set a flag "SameUser" = 1 if the value of the #lastUser is the same
as the current person record we are looking at
if the last user is the same as the previous record
use the #lastTime field as the "lastChange" column
else
use the #ignore field as the last change column
Now, build another flag based on the current record create time
and whatever the #lastTime value is based on a 20 minute interval.
set it to 1 if AT LEAST the 20 minute interval has been meet.
Now the key to the cycling the next record.
force the #lastTime = current record create_time
force the #lastUser = current user
END FOR LOOP
So, if you have the following as a result of the prequery... (leaving date portion off)
create status user sameuser lastchange 20minFlag carry to next row compare
07:34 online Bill 0 09:05 0 07:34 Bill
07:52 idle Bill 1 07:34 0 07:52 Bill
08:16 online Bill 1 07:52 1 08:16 Bill
07:44 online Mark 0 09:05 0 07:44 Mark
07:37 idle Monica 0 09:05 0 07:37 Monica
08:03 online Monica 1 07:37 1 08:03 Monica
Notice first record for Bill. The flag same user = 0 since there was nobody before him. The last change was 9:05 (via the NOW() when creating the sqlvars variables), but then look at the "carry to next row compare". This is setting the #lastTime and #lastUser after the current row was done being compared as needed.
Next row for Bill. It sees he is same as last user previous row, so the SameUser flag is set to 1. We now know that we have a good "Last Time" to compare against the current record "Create Time". So, from 7:34 to 7:52 is 18 minutes and LESS than our 20 minute interval so the 20 minute flag is set to 0. Now, we retain the current 7:52 and Bill for third row.
Third row for Bill. Still Same User (flag=1), last change of 7:52 compared to now 8:16 and we have 24 minutes... So the 20 minute flag = 1. Retain 8:16 and Bill for next row.
First row for Mark. Same User = 0 since last user was Bill. Uses same 9:05 ignore time and don't care about 20 min flag, but now save 7:44 and Mark for next row compare.
On to Monica. Different than Mark, so SameUser = 0, etc to finish similar to Bill.
So, now we have all the pieces and rows considered. Now, take all these and wrap them up as the "FinalAlias" of the query and all we do is apply a WHERE clause for "SameUser = 1" AND "20 Minute Flag" has been reached.
You can strip down the final column list as needed, and remove the where clause to look at results, but be sure to add an outer ORDER BY clause for name/create_time to see similar pattern as I have here.