MySQL triggers: move to trash - mysql

I want to create a trigger in MySQL that will do two things: if forum's topic is located in trash or it is hidden, delete it, elsewhere move the topic to trash. The question is how to stop the delete action in 'before delete' trigger?

I don't know if there's a way to prevent the delete once it has already been called without raising an exception of some sort.
I think a better solution might be instead of calling delete on the record you want to trash/delete you should update a field such as "IsTrashed" to TRUE. And then in the update trigger, see if it was already TRUE and being set to TRUE again (e.g. IF(OLD.IsTrashed && NEW.IsTrashed)). If so, delete it, otherwise move it to the trash.
The only problem that will arise from this method is if you update a different field (e.g. PostDate) of a trashed item, NEW.IsTrashed and OLD.IsTrashed will both be TRUE so it might look like you are trying to delete it, but you are only updating the PostDate. You can either check that this is the only field that was modified (e.g. by checking OLD.SomeField <> NEW.SomeField for every other field) or use a field that will always reset it's value to NULL after an UPDATE statement. Something like "TrashNow". That way if TrashNow ever has a TRUE value, you know that you did intentionally want to trash the field.
However, that "reseting field" is just wasted space, I think the best solution for this problem is a stored procedure... something like:
CREATE PROCEDURE DeletePost (IN APostID INT)
BEGIN
IF ((SELECT InTrash FROM posts WHERE PostID = APostID LIMIT 1))
DELETE FROM posts WHERE PostID = APostID;
ELSE IF
UPDATE posts SET InTrash = TRUE WHERE PostID = APostID;
END IF;
END;
Assuming you have the table posts with the fields PostID (INT) and InTrash (any integer type).
You would call this like so to delete post with PostID 123:
CALL DeletePost(123);

Related

trigger update copy information

I want to create a trigger that does the following:
copy one column of info jobnumber from one table (jobs) to another (materials) on an existing record to attachedjobnumber.
I haven't found the correct syntax to say this. when I insert a new job - nothing gets update and no new row is inserted,,, but there are no error messages in the logs.
I also need to set the bool (hasjobnumber) equal to true - when I test that trigger - it works fine.
which makes me think that setting the value of material.attachedjobnumber = jobs.jobnumber is the problem, my guess is that jobs.jobnumber isn't in reference when updating table material...
if that's true - what's the proper syntax for this?
I've tested separate triggers, and so far this trigger works fine.
UPDATE material
SET isjobyet = "HAS"
WHERE barcode1 IN (
SELECT primaryRFID
FROM jobs
WHERE jobs.primaryRFID = material.barcode1
)
since this code does work - I make the assumption that the non-static JobNumber value is the source of the problem. since "HAS" is correctly updated.
UPDATE material
SET material.AttachedJobNumber = jobs.JobNumber
WHERE barcode1 IN (
SELECT primaryRFID
FROM jobs
WHERE jobs.primaryRFID = material.barcode1
)
from this - I expect that after each inserts on the table jobs:
jobs.JobNumber be assigned to the material.AttachedJobName
this updates only the material row where the material.barcode1 =jobs.primaryrfid.
but no new row is inserted at all.
Before you perform UPDATE,
Actually you can use the same script using SELECT [skip the UPDATE SYNTAX]
That way you can monitor your script without committing anything yet.
And also I dont recommend using this inside the subquery
WHERE jobs.primaryRFID = material.barcode1
This condition connecting a table works on IN-SELECT subquery.
If you are performing subqueries inside the [WHERE] clause, try to treat it as different buffer, dont connect them first.

MSACCESS, how to edit a record after insert using the "after insert" trigger

MS Office 365 ProPlus, Access 2007 - 2016
I'm trying/failing to change the value of a field in a table after it is inserted using the "after insert" trigger. Something like this...
EditRecord
SetField
Name orig_id
Value = [mytable].[id]
End EditRecord
This doesn't seem to work.
USysApplicationLog gives...
SourceObject = mytable.AfterInsert
DataMacro InstanceID = {489D5697-5247-44A8-AE3C-3773A25F72E5}
Error Number = -20335
Category = Execution
Object Type = Macro
Description = EditRecord failed because the default alias represents a record which is read only.
The field is not read only. After the fact I can edit it just fine. I don't know what the "default alias" is nor what that even means.
If the trigger can't do this, can you think of another way to accomplish the same thing ?
You don't want to use the AfterInsert, since then the record is already saved, and tucked away nicely, and everything you need to change in that record is assumed to have been done. In fact, the default context will cause the record in question to be read only. You CAN get around this by pulling the record again, (looking up a record), but if you modify it again then all of the triggers for that record will fire again.
So I ONLY suggest you use this event to sum() or add/edit OTHER tables, but not the record that was just edited and saved.
If you need/want to update this current record, then move your "edit" or "modify" code to the "BeforeChange". This event not only lets you edit/modify right before the save (and thus preventing endless loops in which the update triggers fire again and again), but the CURRENT record is in full context, and you don't even need any "edit record" command, since you have the fresh un-saved record right in context. You thus can use SetField without the need for EditRecord.
So, the AfterInsert is really too late here, and if you could modify the record in that event, you will cause the AfteUpdate event to fire again if you do use a workaround.
Now, if you use BeforeChange, it will fire for both insert and edits (change). So, if your code really only needs to run when inserting, you can check this status by using
If [isinsert] = True then
Edit
Also, it looks like your code is attempting to save (capture) the previous value, and if it is, then you can use:
[old].[id]
Of course this does not make too much sense for "id", since that is usually an autonumber PK column, but for grabbing other values during an update in the BeforeChange event, you can certainly test + inspect the previous (old) values.

How to update multiple records in same table using .AfterUpdate data macro without error "A data macro resource limit was hit."

I have a table tblItems with a list of inventory items. The table has many columns to describe these items, including columns for SupplierName, SupplierOrderNumber and PredictedArrivalDate.
If I order several new items from a supplier, I will record each item separately in the table with the same supplier name, order number and a predicted arrival date.
I would like to add a data macro, so that if I update the PredictedArrivalDate for one record, the value will be copied to the PredictedArrivalDate column of other records/items with the same SupplierName AND SupplierOrderNumber.
The closest I've got is:
SetLocalVar (MySupplierName, [SupplierName])
SetLocalVar (MySupplierOrderNumber , [SupplierOrderNumber ])
SetLocalVar (MyPredictedArrivalDate, [PredictedArrivalDate])
For Each Record in tblItems
Where Condition = [SupplierOrderNumber] Like [MySupplierOrderNumber] And [SupplierName] Like [MySupplierName] And [PredictedArrivalDate]<>[MyPredictedArrivalDate]
Alias OtherRecords
EditRecord
SetField ([OtherRecords].[PredictedArrivalDate], [MyPredictedArrivalDate])
End EditRecord
However, when I run this, only 5 records update, and the error log reports error -20341:
"A data macro resource limit was hit. This may be caused by a data
macro recursively calling itself. The Updated() function may be
used to detect which field in a record has been updated to help
prevent recursive calls."
How can I get this working?
I'm not one for using macro's to do anything, so I'd use VBA and recordsets/an action query to do the updating.
You can call a user-defined function inside a data macro by setting a local var equal to its result.
Access doesn't like data macros triggering themselves (which you are doing, you're using an on update macro and updating fields in the same table on a different record), because there is a risk of accidentally creating endless loops. Looks like you triggered a measure that's made to prevent this. I'd try to avoid that as much as possible.
Note: using user-defined functions inside data macros can cause problems when you're linking to the table from outside of Access (via ODBC for example).
This isn't a good solution (it's not a data macro), but it does work as a temporary fix.
I created an update query called "updatePredictedArrivalDate":
PARAMETERS
ItemID Long,
MyPredictedArrivalDate DateTime,
MySupplierName Text ( 255 ),
MySupplierOrderNumber Text ( 255 );
UPDATE tblItems
SET tblItems.PredictedArrivalDate = [MyPredictedArrivalDate]
WHERE (((tblItems.SupplierName) = [MySupplierName])
AND ((tblItems.SupplierOrderNumber) = [MySupplierOrderNumber])
AND ((tblItems.ID) <> [ItemID]));
On the PredictedArrivalDate form field .AfterUpdate event, I then added this macro:
IF [PredictedArrivalDate].[OldValue]<>[PredictedArrivalDate] Or [PredictedArrivalDate]<>""
OpenQuery (updatePredictedArrivalDate, Datasheet, Edit, [ID], [PredictedArrivalDate], [SupplierName], [SupplierOrderNumber])
I now have to remember to add this .AfterUpdate event to any other forms I create that amend that particular field.
If anyone has a better solution, please let me know.

MySQL trigger not working properly

I'm getting a strange error while trying to use a MySQL trigger.
I'm using XAMPP and creating the trigger using PhpMyAdmin.
The trigger's code is:
BEGIN
DECLARE stud INT(11) DEFAULT 0;
DECLARE sw CURSOR FOR
(SELECT CodiceStudente FROM Listastudenticorsi WHERE CodiceCorso = NEW.CodiceCorso);
OPEN sw;
get_loop: LOOP
FETCH sw INTO stud;
INSERT INTO inbox(Mittente, Destinatario, Oggetto, Contenuto, Data) VALUES (NEW.CodiceDocente, stud, "Nuova news inserita", NEW.Oggetto, NEW.Data);
END LOOP get_loop;
END
And is called BEFORE INSERT into the table 'News'.
What happens is that the syntax is correct, but when I try to run it triggering the event it says "#1329 - No data - zero rows fetched, selected, or processed".
I tried to find out what the real problem is, and it seems to be the line "FETCH sw INTO stud"; I tried many times and the SELECT statement DOES return the correct values, so 'sw' can't be empty... I'm stuck at this point.
There are 3 tables interested by this trigger. 'News' is the one that triggers the event; it has some columns that are called using the keyword "NEW". The second one is Inbox; it is the table in which I'll insert some values after the trigger has performed its actions. Finally, there's "Listastudenticorsi", which means approximately "list of students and courses".
What I do is: when a News is inserted, I get the course it refers to, its object, its date and the submitter of the news, I find (using the select statement) the students who attend the course that the News is referring to, and then send a mail to each of them using the insert statement.
You have no continue handler for the cursor, as I see it. It would allow that cursor to actually do something.
From the mysql Cursor manual page, see this.
Here too is a link to a stored proc I wrote showing a continue handler with a flag specifying done for the loop.

Dynamically selecting MySQL updates

This is more of a theory question. I have a page with a bunch of various textfields, dropdown boxes, etc. Each user has his/her "own page" that can be updated via this update page that I am referring to. He updates the fields at his choosing. It passes about 30 variables (if every field is inputted) to a "preview page". If the person likes the preview page, then they click an "update" button at the bottom of the preview page and all the various variables are updated into the appropriate MySQL table and their "own page" that others see is updated dynamically. (let me know if this explanation isn't clear).
Inserting this information for the first time is easy. However, when a user wants to update only a few of the fields for his page later, this is where I am confused. How do I make the MySQL update query dynamic to recognize an update to ONLY the fields on the page that the user wants to update (while he leaves the other fields blank, thus leaving the old information intact for those columns, and they are disregarded in the update query).
Let me know if what I'm asking doesn't make sense and I'll try again.
Thanks for your help.
The easiest way to do this would be
UPDATE MyTable m SET m.f1 = COALESCE(input1,m.f1), m.f2 = COALESCE(input2,m.f2), ....
WHERE m.id = key;
The COALESCE will return the first non-null value (or null if all values are null).
Note that you can insert a default value after the existing field value if you want to force a default.
Like so:
UPDATE MyTable m SET m.f1 = COALESCE(input1,m.f1,default1), m.f2 = COALESCE(input2,m.f2,default2), ....
WHERE m.id = key;
See: MySQL: how to use COALESCE
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_coalesce