Trigger with condition on multiple rows? - mysql

I am currently implementing some triggers on the tables of my schema, to ensure quality of imported data.
More specifically, one column (let's call it fraction) is supposed to contain only percentages, i.e. values between 0 and 1 but that can sometimes be slightly above 1.
The thing is that in the original datafiles, these values are expressed as percentages, i.e. 80% for 0.8, etc.
Consequently, there is a risk that some users of the database could import data with the wrong order of magnitude, i.e. importing 70 or 80 instead of 0.7 or 0.8.
To prevent this, I have chosen the following criteria : if the mean value of all the rows that the user is trying to import is greater than 2, I want the software to conclude that the user has imported percentages instead of decimal values, and therefore to correct this mistake by dividing all the new values by 100.
The following BEFORE INSERT trigger checks, for each row, whether the value is > 2 or not, and if it is, it divides the value by 100:
CREATE DEFINER=`admin`#`localhost` TRIGGER `myschema`.`percentage_trigger` BEFORE INSERT ON `mytable` FOR EACH ROW
BEGIN
IF NEW.fraction > 2
THEN
SET NEW.fraction = NEW.fraction/100 ;
END IF;
END
but my question is: how to have a criterion that sounds like "the mean of all the new values is > 2" instead of a criterion like "this value is > 2"?

Related

How do I replace values in a column in KNIME?

I have a column of countries with 50 different values that I want to reduce to United States and Other.
Can someone help me with that?
Another example is Age which has 48 values that I'd like to reduce to only 4 like 1 to 18 = youth, 18-27 = starting, etc.
I've actually got about 5 columns that I want to reduce the values of. So would I need to repeat the process multiple times in KNIME or can I accomplish multiple column value replacements at once?
The latter on can easily be achieved with the Rule Engine
$Col0$ > 1 AND $Col0$ <18 => "youth"
For the First problem I'd use a String Replace (Dictionary).
I don't think you replace all at once but you can loop over columns.
For the second case I would use Numeric Binner:
For each column a number of intervals - known as bins - can be
defined. Each of these bins is given a unique name (for this column),
a defined range, and open or closed interval borders. They
automatically ensure that the ranges are defined in descending order
and that interval borders are consistent. In addition, each column is
either replaced with the binned, string-type column, or a new binned,
string-type column is appended.

Access 2013 Count

I am working on a report in Access 2013 I need to seperate the first 20 records in a column that contain a value and assign a name to them. Such as at 1-20 I need it to insert Lot 1 at 21-40 need to assign Lot 2 etc... The report needs to be separated by lots of 20. I can also just insert a line when it reaches sets of 20 without a name if that makes it easier. Just need something to show a break at sets of 20.
Example: As you can see the report is separated by welder stencil. When the count in the VT column reaches 20 I need to enter a line or some type of divider to separate data. What our client is asking for is we separate the VT in sets of 20. I don't know whats the easiest way to accomplish this. I have researched it but haven't found anything.
Example Report with Divisions
Update the report's RecordSource query by adding "Lot" values for each row. There are multiple ways of doing this, but the easiest will be if your records already have a sequential, continuous numerical key. If they do not have such a key, you can research generating such sequential numbers for your query, but it is beyond the scope of this question and no details about the actual data schema were supplied in the question.
Let's imagine that you have such a key column [Seq]. You use the modulo (mod) and/or integer division operators (\ - backslash) to determine values that are exactly divisible by 20, e.g. ([Seq] - 1) mod 20 == 0.
Generate a lot value for each row. An example SQL snippet: SELECT ("Lot " & (([Seq] - 1) \ 20)) As LotNumber ...
Utilize Access report sorting and grouping features --grouping on the new Lot field-- to print a line and/or label at the start of each group. You can also have the report start a new page at the beginning or end of such a group.
The details about grouping can be found elsewhere in tutorials and Access documentation and are beyond the scope of this question.

zabbix - trigger on multiple items greater than 0

I have multiple items that are traps that return an integer such as below.
app.tidal.Health.HighPriority.MessagesInQueue
app.tidal.Health.CommDefault.MessagesInQueue
app.tidal.Health.Default.MessagesInQueue
I want to create a trigger if two or more of these has returned a value of greater than 0 in the last 3 checks to send a severity High message.
I'm having a hard time trying to devise my trigger this is what I currently have:
{Template_App_Tidal_Masters:app.tidal.Health.CommDefault.MessagesInQueue.min(#3)}>0 and
{Template_App_Tidal_Masters:app.tidal.Health.Default.MessagesInQueue.min(#3)}>0 and
{Template_App_Tidal_Masters:app.tidal.Health.HighPriority.MessagesInQueue.min(#3)}>0
But obviously it won't work as it's an and statement so all 3 would have to be greater than 0 the last 3 checks. Formatted the trigger on 3 lines to make it clearer.
This should work:
({Template_App_Tidal_Masters:app.tidal.Health.CommDefault.MessagesInQueue.min(#3)}>0) +
({Template_App_Tidal_Masters:app.tidal.Health.Default.MessagesInQueue.min(#3)}>0) +
({Template_App_Tidal_Masters:app.tidal.Health.HighPriority.MessagesInQueue.min(#3)}>0) > 1
Each part first evaluates an individual item to be larger than 0. If that is true, that part of the expression evaluates to 1, if false - to 0. In the end we sum up the results of these evaluations (not the original item values) and check whether two or more items had values larger than zero.

Mysql auto-increment partially by today's date only - is this possible?

I have a requirement to auto increment an integer which I need "for the day". This is used for box numbers for orders being sent out in a day through our client's e-commerce website.
For example, the first order today would contain the box number 01. The second order would contain 02. This would be incremented specifically by a trigger or some kind of automatic function, depending on the date.
What I have described is not my exact/full requirement but I would like to know how I can code the above in particular? So if we imagine a table like this:
myboxnumbers (boxid [auto increment], yyyymmdd-date, boxno)
I would like a function in Mysql (stored procedure) to 'give me the next increment of the box number for today').
E.g.
function generateBoxNoForToday() {
//1. Get today's date
//2. Check the latest boxno in the above table for today
//3. If no boxno yet for today, set $new-boxno = 1
//4. If there is a boxno, my new $new-boxno = boxno + 1
//5. INSERT INTO myboxnumbers (yyyymmdd-date, boxno) VALUES (today(), $new-boxno)
}
Please guide on how could I actually "do" this in Mysql? I suppose I'm too used to PHP so it's tempting to do it there :) but it makes sense that this is purely a database function and so I would like to do how to do this and the easiest route to take for such a function?
Many thanks!
It's not hard to put this into your insert statement for this table. As #AlmaDo pointed out, you need to lock the table and avoid the COUNT(*) operator, however.
Issue these three sql statements one after the other. Don't do anything else until you've issued all three, or your system may fail to scale up when you need it to.
LOCK TABLES myboxnumbers WRITE;
INSERT INTO myboxnumbers
(yymmdd_date, boxno)
VALUES
(TODAY(),
SELECT 1 + IFNULL(MAX(boxno),0)
FROM boxnumbers
WHERE yymmdd_date = TODAY()
);
UNLOCK TABLES;
To make this efficient, you need an index on (yymmdd_date,boxno).
To retrieve the just-inserted boxno value, you can do this immediately after your UNLOCK TABLES statement.
SELECT boxno FROM myboxnumbers WHERE boxid = LAST_INSERT_ID()

How to determine if a field/column is affected by an UPDATE statement

Hello everyone and thank you for your answers and comments.
I have a table with several fields, among which are version, last_modified and modified_by
I'm writting a trigger to:
increase version by 1 after every/any update,
set last_modified to the current timestamp,
set the id of the user who made the latest changes into modified_by, and
prevent the programmer from ignoring/forgetting to set modified_by = userid in the UPDATE statement by raising a signal (in such case).
How can I achieve this?
I tried checking if isnull(NEW.modified_by), but then realized that NEW.modified_by takes the same value as OLD.modified_by if it wasn't affected. Also, checking if NEW.modified_by equals OLD.modified_by doesn't quite make it, since it could be a user modifiyng a record previously modified by himself.
Is there a way to determine which fields where affected by the UPDATE statement? Or if a particular field (modified_by) was affected?
I cannot find anything that will allow you to inspect the incoming information to see which fields are being affected. While I know you are trying to stop this issue at the trigger level, it might be prudent to require all table writes to go through a stored procedure. That way you could require the user field.
If that isn't a possibility, I think you might need to get tricky. For example, you could require that the user_id be written to two fields (create an extra column that is blank for this purpose). Then, compare the user_id in the dummy column to the one you are updating. Once you figure out if you need to modify the user_id or not, blank out the dummy column again. It isn't pretty, but it would get the job done.
I had a similar issue. I have a table with a tinyint column named isDirty, and wanted to set it to 1 when the row is updated, and clear it to 0 when the row has been "cleaned".
The problem is, the combination of NEW and OLD with values of 0 and 1 didn't give me enough values to solve my problem. So instead, I made a "rule" that when the column was updated to a value of 100, it was set to the clean value of "0", anything else set it to "1". The reason this works is that this column will only ever have one of 2 values, 0 or 1, so you can use 100 (or any value of your choice) as the "flag" that indicates that it is clean.
I know that it sounds a little backwards to set it to a non-zero value to get back to 0, but that's the direction I chose and it works. Here's what that trigger looks like:
CREATE TRIGGER calls_update BEFORE UPDATE ON `calls`
FOR EACH ROW
BEGIN
IF ( NEW.isDirty = 100 ) THEN
SET NEW.isDirty = 0;
ELSE
SET NEW.isDirty = 1;
END IF;
END
$$
As far as I know, your only option is to check each column's NEW value against the OLD.
SET `ColumnAChanged` = NEW.ColumnA <=> OLD.ColumnA;
SET `ColumnBChanged` = NEW.ColumnB <=> OLD.ColumnB;