MySQL Trigger Setting All Other Values to NULL When Run - mysql

I have two tables, Accounts and Person:
CREATE TABLE Person(
id INT NOT NULL PRIMARY KEY,
Person_Name VARCHAR(17) NOT NULL,
P_Location INT NOT NULL
);
INSERT INTO Person VALUES (1,"Adam",300),(2,"Betty",10),(3,"Louis",60);
CREATE TABLE Accounts(
Person_id INT PRIMARY KEY,
Balance INT DEFAULT 200);
INSERT INTO Accounts VALUES (1,2000),(2,1350),(3,800);
And one trigger, Bonuses:
CREATE TRIGGER Bonuses
AFTER UPDATE ON Person
FOR EACH ROW
UPDATE Accounts
SET Balance = CASE WHEN (SELECT P_Location FROM Person WHERE id = Person_id) = 3 THEN Balance - 150
WHEN (SELECT P_Location FROM Person WHERE id = Person_id) = 7 THEN Balance + 100
WHEN (SELECT P_Location FROM Person WHERE id = Person_id) = 15 THEN Balance - 30
WHEN (SELECT P_Location FROM Person WHERE id = Person_id) = 1 THEN Balance + 200
END;
And I want to make the trigger update the Accounts table according to certain instructions whenever the P_Location on the Person table changes to one of a select few values (3,7,15 and 1). However, as things are they result is incorrect. Assume I run the above code, the tables I get are:
Person
id
Player_Name
P_Location
1
Adam
300
2
Betty
10
3
Louis
60
Accounts
Person_id
Balance
1
2000
2
1350
3
800
Now if I run UPDATE Person SET P_Location = 3 WHERE id = 1; then the Accounts table should yield:
Person_id
Balance
1
1850
2
1350
3
800
However, what I get is
Person_id
Balance
1
1850
2
NULL
3
NULL
Any idea of what I'm doing wrong?

Well, that code did exactly what you said, though it wasn't what you meant!
That's the thing about UPDATE queries, EVERY row will get an update unless a WHERE clause is used to filter what actually gets modified. Nothing is found from the CASE with most records, so any of those will get assigned to NULL. To see this behavior, check this fiddle example.
However, there is good news, all that is needed in the trigger is to add a WHERE clause. Note that I simplified the CASE handling make use of the UPDATE trigger's NEW references:
CREATE TRIGGER Bonuses
AFTER UPDATE ON Person
FOR EACH ROW
UPDATE Accounts
SET Balance = CASE WHEN NEW.P_Location = 3 THEN Balance - 150
WHEN NEW.P_Location = 7 THEN Balance + 100
WHEN NEW.P_Location = 15 THEN Balance - 30
WHEN NEW.P_Location = 1 THEN Balance + 200
END
WHERE Person_id = NEW.id;
So starting with:
Then run: UPDATE Person SET P_Location = 3 WHERE id = 1;
Gives:
Example fiddle with your tables, the simplified trigger case handling, and the output examples from the update query.

Related

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.

SQL: update value based on following rows data

I have a table customer_service_types in phpmyadmin with these fields:
id (int) | customer_id (int) | service_type_int (int) | price (decimal) | created (datetime) | card (tinyint)
Here are some entries:
The application when the user adds a new service for a customer with a custom created date, is creating another service with id : 3 (payment) with today's date. I want to update all payments with the date of the following services.
So what I want to do is update the created field of the payments with the created value of the following services for specific client. So for example I need to update created of id: 168 with the value of created for the same customer_id but only of the following row if it has service_type_id != 3.
Tried so far:
UPDATE customer_service_types cst
SET cst.created = (SELECT created
FROM customer_service_types cst2
WHERE cst.id = (cst2.id - 1) AND cst2.service_type_id <> 3
)
WHERE cst.service_type_id = 3;
But I get this error:
You can't specify target table 'cst' for update in FROM clause
And I don't know if this query will produce the desired result
You can transfer your subquery to a Derived Table form instead. Try the following:
UPDATE customer_service_types AS cst
JOIN
(
SELECT id, created
FROM customer_service_types
WHERE service_type_id <> 3
) AS cst2
ON cst.id = (cst2.id - 1)
SET cst.created = cst2.created
WHERE cst.service_type_id = 3;
You can use a join:
UPDATE customer_service_types cst JOIN
customer_service_types cstnext
ON cstnext.id = cst.id and cstnext.service_type_id <> 3
SET cst.created = cstnext.created
WHERE cst.service_type_id = 3;

updating the column of a table with different values

I have a table called person there are about 3 million rows
I have added a column called company_type_id whose default value is 0
now i want to update the value of company_type_id to 1
where person_id from 1 to 212465
and value of company_type_id to 8 where person_id from 256465 to 656464
how can i do this
I am using mysql
You can do that in one update statement:
update person
set company_type_id = 1
where
(person_id >= 1 and person_id <= 212465) or
(company_type_id = 8 and person_id >= 256465 and person_id <= 656464)
update person set company_type_id=1 where person_id>=1 and person_id<=212465;
I am sure you'll make the second update query by yourself.
Two SQLs:
1:
UPDATE person
SET company_type_id = 1
WHERE person_id BETWEEN 1 AND 212465
2:
UPDATE person
SET company_type_id = 8
WHERE person_id BETWEEN 256465 AND 656464

Display column name of most recently updated column

I am wondering if it is possible to display the column name of the most recently updated column in a table.
Example:
**Original Record created on 03/20/14:**
Name: John
Height
Weight
Age
Update_date: 03/20/14
Update_Column: Name
Then someone comes in and updates the height on 03/22/14:
Name: John
Height: 5'9
Weight
Age
Update_date: 03/22/14
Update_Column: Height
And the Update_date and Update_column would change again if someone came in and put a value for age. And so on.
Is this possible?
Also, if the above is possible, would it be possible to display the column name farthest right if a user updated more than one column at the same time?
Example:
User updates the below record:
Name: John
Height: 5'9
Weight
Age
Update_date: 03/22/14
Update_Column: Height
And adds in a weight and age at the same time on 03/24/14:
Name: John
Height: 5'9
Weight: 150
Age: 31
Update_date: 03/22/14
Update_Column: Height
The Update_Column would display Age because it is the farthest to the right. (Thinking of it as you read from left to right, so the column that was last updated would be the one farthest right)
So to sum things up, I need to be able to display Updated_date(which will be the current date when the record is last updated) and Updated_Col (which is the column name of the last column that was updated, and if multiple columns are updated then display the one that a value was updated last in)
Hopefully the examples help to clarify things.
Thanks,
Steven
You need to store those meta data for each row. So you'd need two new columns, the update_date and update_column. Then you can add an before update trigger to check which columns are about to change and set the update date.
update
Here's an example:
delimiter //
create table a (
id int (10) unsigned auto_increment,
a int(10),
b int(10),
update_date datetime NULL,
update_column varchar(16) NULL,
primary key (id)
)//
create trigger bu_a before update on a for each row begin
set NEW.update_date = NOW();
set NEW.update_column = NULL;
-- you need to start with the rightmost column if you want
-- that matched with the highest priority
if OLD.b != NEW.b then
set NEW.update_column = "b";
elseif OLD.a != NEW.a then
set NEW.update_column = "a";
end if;
end //
Test:
insert into a (id,a,b) values (1,1,1), (2,1,1), (3,1,1), (4,1,1)[
update a set b = 2 where id = 2;
update a set a = 2 where id = 3;
update a set a = 2 where id = 4;
update a set b = 2 where id = 4;
select * from a;
Output:
ID A B UPDATE_DATE UPDATE_COLUMN
1 1 1 (null) (null)
2 1 2 March, 24 2014 23:22:33+0000 b
3 2 1 March, 24 2014 23:22:33+0000 a
4 2 2 March, 24 2014 23:22:33+0000 b

Update access column from existing values

I have a MS access table with the following columns and sample records.
How do I update the adDate value with the least LastSaleDate for each ProductID.
orderID productID lastsaleDate adDate
1 1 10/20/2012
2 1 5/10/2007
3 1 4/1/2004
4 1 20/11/2011
5 2 10/10/2010
6 2 12/10/1972
For example the adDate for ProductID 1 will be 4/1/2004
and for ProductID 2 will be 12/10/1972
You can use DMin:
UPDATE sales
SET sales.adDate = DMin("lastsaleDate","sales","productID=" & productid)
Unless you have a compelling reason to actually store adDate values in your table, consider simply computing adDate with a query any time you need it. That way you don't risk ever displaying adDate values which have not been updated to reflect the latest changes to the underlying data.
SELECT
y.orderID,
y.productID,
y.lastsaleDate,
sub.adDate
FROM
YourTable AS y
INNER JOIN
(
SELECT productID, Min(lastsaleDate) AS adDate
FROM YourTable
GROUP BY productID
) AS sub
ON y.productID = sub.productID;