Dynamically selecting MySQL updates - mysql

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

Related

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 can I clear a specific filter without clearing all filters?

Background:
I am creating an app that stores record of trainings that employees in a company took in table. I want to filter the rows of the table based on training name and/or employee name. I was able to figure out this first part, and I was able to create a button that clears all the filters and reloads the entire table using the clearFilters() function.
Problem:
I want to create two buttons that clear the filter selections one ("All Trainings") for the training name and one ("All Employees") for the employee name. To be more clear, when I click on the "All Trainings" button, I want to clear the filters on the training name, but not on the Employee name. This will become useful once I have a table with multiple fields that I want to filter, and I want to navigate the table without having to reset all fields every time.
I tried searching the functions available on Google App Maker, but there was nothing that seemed to be able to solve my problem. Any suggestions?
From the Reference about datasources:
https://developers.google.com/appmaker/models/datasources#query_datasources
Like field filters, assigning null to a relation filter property clears that restriction.
So, something like:
datasource.query.filters.Employee._contains = null;
datasource.load();
should work for you.
I am sure there is a better way to do this, so you may want to wait for someone smarter to chime in, but I BELIEVE you can just have your button clear the filters, but reapply a new filter.
So for my situation I have the table do a filter for items that are listed as "Complete", so those are hidden when the user opens the page.
Then, when the users filter another field and want to clear out that search I didn't want the "Complete" items to reappear (which is what happened when I just used the clearFilters() function. So my workaround was to make the clear button actually clear the filter, but apply the original "Complete" filter.
So for my OnClick action, for my "Clear Button" I have:
widget.datasource.query.clearFilters();
widget.datasource.load();
app.closeDialog();
var datasource = app.datasources.TestModel;
datasource.query.filters.Status._notContains = 'Complete';
datasource.load();
The
widget.datasource.load();
app.closeDialog();
May be redundant/unnecessary.
Can you simply take 3 steps in your onClick handler?
(1) clear all filter
(2) set the employee name filter
(3) load data

Duplicate row and everything related to that ID in different tables

I'm working on a software for managing the Rally company of my boss, where he can manage all the volunteers, their affectations, and many other things.
But the volunteers and these others things vary depending on the event, so they all have a column representing the event that they are linked/related to.
My boss requested that I add a "duplicate" button, that would duplicate an event (from my events table) and also duplicate all the volunteers, and values from any other table that is linked to that event, so the new duplications are linked to the new event.
The reason for this, is that he is constantly organizing rallies, and often it happens that the data from a Rally (event) to another is almost the same, so instead of adding it all manually, he'd rather make an entire duplication of the event and all the data related to it, then manually add and remove the errors in it.
I would like to know, is there any way in MySQL that I could duplicate an event, and everything that is linked to it's ID, even though they are in different tables, and make the duplications have the ID of the new event?
Sadly I don't have very much time, but until I get an answer I can work on other tasks my boss gave me.
Thank you so much to anybody who helps me or gives me any hint!!
EDIT:
Here's the schema of my Database (I know it's kinda dirty and there's issues with it, my boss gave me indications on how to create the database since he used to work in the domain before, but he didn't tell me how to make the links and he wants to make them himself)
And I apologize for the French language and the weird names..
Basically I wish to duplicate an entry in the "event" table, all the "affect" and "lieu" entries that are linked to it, and all the "tache" entries related the the duplicated "lieu" entries.
EDIT 2:
Thank you MrMadsen for the Query!
I had to fix it a bit, but here's what it looks like after.
SET #NEWEVEN = (SELECT MAX(NO_EVE) from db_rallye.event)+1;
INSERT INTO db_rallye.event
SELECT #NEWEVEN,
NM_EVE,
AN_EVE,
DT_EVE,
NM_REG_EVE
FROM event
WHERE NO_EVE = event_to_duplicate;
SET #NO_AFFECT_LIEU = (SELECT MAX(NO_AFF) from db_rallye.affect);
INSERT INTO db_rallye.affect
SELECT #NO_AFFECT_LIEU:=#NO_AFFECT_LIEU+1,
CO_AFF,
DT_AVI_AFF,
DS_STA_AFF,
CO_STA_AFF,
NO_BRA_EVN,
NO_PERS,
#NEWEVEN,
NO_EQU,
NO_LIE,
NO_PERS_RES,
IN_LUN,
IN_BAN,
DS_HEB,
IN_HEB_JEU,
IN_HEB_VEN,
IN_HEB_SAM,
NO_BOR,
NO_TUL_CAH,
NB_SPEC
FROM affect
WHERE NO_EVEN = event_to_duplicate;
INSERT INTO db_rallye.lieu
SELECT NO_LIE,
#NEWEVEN,
CO_LAT,
CO_LON,
FI_IMA,
FI_CRO,
FI_TUL,
DS_LIE,
DS_COU,
DS_LON,
NB_BLK,
VL_KM,
IN_FUS,
VL_DIS_FUS,
NO_LIE_FUS_SUI
FROM lieu
WHERE NO_EVEN = event_to_duplicate;
SET #NO_AFFECT_TACHE = (SELECT MAX(NO_TAC) from db_rallye.tache);
INSERT INTO db_rallye.tache
SELECT #NO_AFFECT_TACHE:=#NO_AFFECT_TACHE+1,
NO_LIE,
#NEWEVEN,
NO_AFF,
DS_REP,
DS_TAC
FROM tache
WHERE NO_LIE IN
(SELECT NO_LIE FROM lieu WHERE NO_EVEN = event_to_duplicate);
If a lot of the events contain similar information than I would create a template (or templates and the ability to create/modify templates) containing all of the information that you would duplicate.
Then when a new event is created he can just choose a starting template and then only add whatever data is unique to that event. In my opinion this would be much better than constantly duplicating the data.
As far as how to duplicate a row and all the associated rows, this is completely dependent on your database schema and how the tables relate to one another. If you post the relevant part of that we can help you more.
Edit
Here are the queries I came up with, test them in a dev database first but I think they will work. Let me know. Good luck!
INSERT INTO `event`
SELECT NULL NO_EVE,
NM_EVE,
AN_EVE,
DT_EVE,
NM_REG_EVE
FROM `email_log`
WHERE id NO_EVE = id_of_event_to_duplicate
INSERT INTO `affect`
SELECT NULL NO_AFF,
CO_AFF,
DT_AVI_AFF,
DS_STA_AFF,
CO_STA_AFF,
NO_BRA_EVN,
NO_PERS,
NO_EVEN,
NO_EQU,
NO_LIE,
NO_PERS_RES,
IN_LUN,
IN_BAN,
DS_HEB_JEU,
IN_HEB_VEN,
IN_HEB_SAM,
NO_BOR,
NO_TUL_CAH,
NB_SPEC
FROM `affect`
WHERE NO_EVE = id_of_event_to_duplicate
INSERT INTO `lieu`
SELECT NULL NO_LIE,
NO_EVEN,
CO_LAT,
CO_LON,
FI_IMA,
FI_CRO,
FI_TUL,
DS_LIE,
DS_COU,
DS_LON,
DB_BLK,
VL_KM,
IN_FUS,
VL_DIS_FUS,
NO_LIE_FUS_SUI
FROM `lieu`
WHERE NO_EVEN = id_of_event_to_duplicate
INSERT INTO `tache`
SELECT NULL NO_TAC,
NO_LIE,
NO_EVEN,
NO_AFF,
DS_REP,
DS_TAC
FROM `tache`
WHERE NO_LIE IN
(SELECT NO_LIE FROM `lieu` WHERE NO_EVEN = id_of_event_to_duplicate)

MySQL modify values of one column based on contents of another

Basically I want to query a database and modify the values of one column based on the contents of another.
Here's my idea of how it would work:
IF Column 'Town' IS NOT NULL then Column 'Sign-up type' = 1 else = 0
The logic is, i've added a new column into the DB that will store whether a quick or full sign up has been made.
Quick = 0, Full = 1. Default is 0 = Quick.
I've managed to implement the change on the two registration forms that feed the DB, but I need to append the historical data to backwards fill the data.
Because the quick sign up only collects name, and email, those entries do not contain data in the 'Town' field which is a required field in a full sign up.
So i'm using that as a reference point to select all the entries that DO have (NOT NULL?) data in order to enter '1' (representing 'Full') into 'Signup Type' column.
I hope I'm making sense! I only have a basic understanding of MySQL but I'm willing to learn, it's sometimes hard trying to explain what I want to do when I'm unclear of the correct jargon!!
UPDATE yourTable SET signupType = IF(Town IS NULL, 1, 0);
Note this will update all data, you may want to limit this to historical data (by the sounds of things this should be fine however).

MySQL triggers: move to trash

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);