[MySQL]Insert a value depending on a condition - mysql

I'm studying MySQL so I'm a bit new to all this stuff, but the last time I asked you guys, you proved to be really helpful, so perhaps you can help me again because I haven't been able to find the answer on my own.
Ok, so the thing is, I need to add a new column to an already existing table, and it should be like:
ALTER TABLE `medicos`
ADD COLUMN `tipo_medico` VARCHAR(20) NOT NULL DEFAULT 'indiferente' AFTER `sueldo`;
Now I'm supposed to run an INSERT instruction to add the data there. After adding that column, the table looks like this:
These values equal to: Medic_number, Surnames, Speciality, Day of birth, University, Wage and Medic_type (the new column I've added). The data I add on all the columns except the last one doesn't really matter, but the last column must be filled following the next conditions:
-By default, it'll be "indiferente" (that's working).
-If a medic has studied in an university ending in -a (i.e. Valencia), it'll say "Excellent".
-If a medic is 40 years old or older, it'll say "Expert".
Now, I know how to do these conditions ("... university like = '%a'", etc), but I don't know how to add that into the INSERT instruction. This is what I've gotten so far:
insert into medicos values ('A021', 'Apellidos :D', 'Loquesealogia', '1970-03-14', 'Valencia', '3500');
That adds everything but the last column, which is the one where I'm lost. What can I do to tell the INSERT instruction to, depending on which of the previously named conditions are true, add one value or another?
I hope I've been clear enough, I'm not a native English speaker so I'm sorry if that wasn't good enough. Also I've tried to format the codes this time, I hope that'll work.
Thanks.

This seems to be a case when we need to apply a logic on column values before a record is inserted. I would suggest creating a BEFORE INSERT trigger on this table, which will be automatically executed by MySql before each record is inserted.
We can write the logic to determine the value of last column depending upon values supplied for the other columns. Have a look at this link for trigger example.
If the requirement here is to do a one time bulk insert then, we can drop this trigger once insertion is complete.

I would advise you to do it either with BEFORE INSERT trigger as Darshan Mehta recommends, or do your logic in the programming side, or with a stored procedure.
Still it is doable at query time, so to answer your question specifically, try something like this:
INSERT INTO medicos (num_colegiado, apellidos, especialidad, fecha_nac, universidad, sueldo, tipo_medico) SELECT 'A021', 'Apellidos :D', 'Loquesealogia', '1970-03-14', 'Valencia', '3500', IF('Loquesealogia' like '%a','Excellent',IF(DATE_ADD('1970-03-14', interval 40 YEAR)>NOW(),'Expert','indiferente'))

Related

selectively UPDATING old rows when INSERTING new ones into table (trigger issue) in MySQL

I've come across a slight issue when designing a trigger statement in our MySQL DB today:
We have the following relevant tables:
quote (quote_key, date, discount_rate, discount_period, supplier_key)
part (part_key, part_name, ...)
part_quote (pq_key, part_price, fk_quote_key, fk_part_key)
part_approval (papproval_key, is_approved, fk_part_quote_key)
Now for an explanation of the logic:
Every supplier issues quotes for different inputs into a manufacturing process (e.g. parts and components). If the price for a part is about right, they will be approved for manufacturing and can thus be used by our engineers. Since we want to be able to receive quotes from different suppliers for the same parts to enable a comparison, I've tried to model this process by using the part_quote and part_approval table.
On to my problem: If I want to approve a new part_quote, I would like the BOOL flag "is_approved" in all (or the most recent) old quotes to be automatically set to FALSE.
I tried to get this done by issuing a trigger statement:
CREATE TRIGGER update_approval BEFORE INSERT ON part_approval
FOR EACH ROW --- ??
I have some problems selecting the right rows to update:
How do I select the part_key, which will ultimately identify all relevant rows that require updating?
How do I select only the old (or most recent) rows?
I would have loved to include a screener but unfortunately, I do not have 10reps yet :/
Thank you so much in advance,
All the best,
Marius
First I will answer your question as-is to the best of my ability since it is helpful to know more about how to use triggers. Then I will explain why you shouldn't actually be using triggers.
Triggers provide access to two special aliases, which are not otherwise available: OLD and NEW. NEW lets you access the new values and works in update/insert triggers. OLD lets you access the old values and works in update/delete triggers.
For your case you would probably want something like this:
CREATE TRIGGER `update_approval` BEFORE INSERT ON `part_approval`
FOR EACH ROW
UPDATE `table_x` SET `value` = y WHERE `z` = NEW.a;
For more information and some useful examples of triggers, I would suggest reading this: http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
HOWEVER, triggers in MySQL cannot update the same table which they were triggered on, which is what you are looking to do. There is a good question someone had relating to this here: MySQL - Trigger for updating same table after insert and a good answer that you should use a stored procedure in this case.
I'm not sure this will solve my problem entirely, but based on your suggestions I came across a couple of helpful posts, that were able to implement similar updates within a trigger with multiple statements.
CREATE TRIGGER update_approval BEFORE INSERT ON part_approval
FOR EACH ROW BEGIN
DECLARE part_id INT;
SELECT part_key INTO part_id
FROM part p, part_quote pq, part_approval a
WHERE NEW.part_quote_key=pq.part_quote_key AND pq.part_key = p.part_key;
UPDATE part p, part_quote pq, part_approval a
SET a.is_approved=DEFAULT
WHERE pq.part_key=part_id AND a.approval_date<NEW.approval_date;
END;
will only be able to try it out on monday after the DB has been populated.
thanks for the help!

how to insert if exist update (no unique key)

i have 3 tables (sample),no key restrictions
one is FRUITTABLE, second is FRUITPRICE, third is COMBINATIONS
in FRUITTABLE, we insert what is being sold, color(ie,banana green or yellow),taste,
in FRUITPRICE, we insert how many piece, if applicable pack and the time it was sold
this is how i create combinations
SELECT FT.FRUITS, FT.COLOR, FT.TASTE, COUNT(FP.SALES) AS TOTAL, FP.TIMESOLD
FROM FRUITSTABLE FT
JOIN FRUTSPRICE FP ON FT.ID = FP.ID
WHERE FP.TIMESOLD BETWEEN '2013-12-01 11:00:00' AND '2013-12-01 12:00:00'
GROUP BY FT.FRUITS, FT.COLOR, FT.TASTE
in the COMBINATIONS table, what we do is we group it and count so we will see what is most likely good fruit combination per hour
SO COMBINATIONS WILL OCCUR ONCE EVERY HOUR
lets say
ie: mango,yellow,sour,10, 3:00PM
ie: mango,yellow,sour,12, 4:00PM
ie: mango,yellow,sour,14, 5:00PM
ie: mango,yellow,sour,10, 6:00PM
so evey hour, lets say 3:00PM
we insert
mango,yellow,sour,1, 3:00PM
then another customer bought this combination at the same hour so the data will be
mango,yellow,sour,2, 3:00PM
now, in combinations, we insert it. but if the combination already exist,
i honestly dont know how i can update it..
we need to update it lets say every 5min, maybe i can manage to create SP and EVENT that will
call SP(hoping this is correct)
the only problem is i dont know how to:
select, insert, if exist(the combinations of FT.FRUITS, FT.COLOR, FT.TASTE are same) update
pls let me know if what im thinking is possible or not..
thanks in advance
PS. i already used insert on duplicate key update in some cases
PS. we determine the group combination and total sales(FP.SALES) per hour(TIMESOLD)
EDIT
PS replace into is not applicable as well
also the reason why i cant use a unique key is because it will be useless..
because each combination will occur every hour.. honestly,
i already have solution. but it wont be updated every minute,
my solution will be insert it every hour.
the negative side of doing that is the record in the webpage will not be in real time
all i need to figure out is how i can do something LIKE
insert on duplicate key update (but without using primary key)
so that the table will be updated and the record will be in real time
if its possible to create a workaround
sorry if i have to edit the question many times. i hope this one is constructive.. thank you for your help guys...
You are probably looking for this :
Insert to table or update if exists (MySQL)
OR:
You can actually make the combination (of FT.FRUITS, FT.COLOR, FT.TASTE) a key such that they can individually have multiple values but there will be unique combinations of them in the table.
Creating a Compound Key http://en.wikipedia.org/wiki/Compound_key would be the right solution. However, if you are not able to create keys for whatever reason, do it the other way round:
UPDATE myTable SET [whatever goes here] WHERE FRUITS = [currentFruit] AND COLOR = [currentColor] AND TASTE = [currentTaste]
Now, use your programing language and retrieve the affected row count. If it's 1 - you're done. If it's 0: You need to insert, because there was no row matching your update statement.
Just in case, if you are using load data statement instead of insert(like reading from csv or customized delimited file). You can use the replace flag.
http://dev.mysql.com/doc/refman/5.1/en/load-data.html

Updating MySQL fields only when other information in the row changes

I have a problem where I would like a field to work in a similar way to the timestamp type field, where it only gets updated on an update if there are other changes to the record.
I am using php to update a mysql database with myisam tables.
Take the following example table which has one row with the following fields;-
UNIQUEID : 1
TITLE : Example
AMENDAT : (timestamp)
AMENDBY : Andy
I have some code which handles maintenance on the table. The update to the table uses (for example) the following statement ;-
update example set TITLE="New Title",AMENDBY="Andy" where UNIQUEID=1 ;
This statement works fine and updates the row including the AMENDAT timestamp field.
If a different user makes the same change;-
update example set TITLE="New Title",AMENDBY="Bob" where UNIQUEID=1 ;
Again, everything works as expected.
But, it is possible that the update statement may be called when no changes have been made to any of the columns in the statement (this is possible in the real world because I have a large number of fields in the table which are all updated at once and I do not wish to code a check on the before and after values of the fields - I just let the update take the strain);-
update example set TITLE="Example",AMENDBY="Andy" where UNIQUEID=1 ;
In this case, MySQL decides that nothing need be done, so it does not update the AMENDAT timestamp (all good so far).
But if another user does the same thing;-
update example set TITLE="Example",AMENDBY="Bob" where UNIQUEID=1 ;
Then the row is updated due to the change in the AMENDBY field. So even though the actual data has not changed, the amendment details have (which is not good for my amendment tracking).
My current work around for this problem is to use the following statement for updates;-
update example set TITLE="XYZ",AMENDBY="XYZ",AMENDAT=NULL where UNIQUEID=123 ;
This forces an update every time, so the amendment details will reflect the last user to save the record whether or not they made any changes. Obviously this is not ideal.
Is there any way of making the AMENDBY field update only when there are changes to other fields on the record, much like the default functioning of a timestamp type field?
I realise this problem is easily solved by making two separate calls to MySQL, one to do the update and check from the return (number of records updated) whether to make a second call to update the amendment details, but this is a messy and not very elegant solution.
Bear in mind that I have a large number of tables which are set up in the same way, each has an arbitrary number of fields, so I don't want a solution which requires an enormous call to MySQL which includes an if statement for every field which may or may not be updated.
I think that what you are trying to do can be achieved with a TRIGGER with timing AFTER on the UPDATE event. Triggers can be tricky though, use them with extra caution. Also bear in mind, that if the trigger statement fails for some reason the actual UPDATE/INSERT/DELETE fails too.

MySQL intelligent default value

I'm adding stuff to a MySQL table, and each item has a position that it shows up in my system like a question number.
I could find out what the largest position is before adding a new question, +1 it, and then add it - but I was wondering if there's a more intelligent way that doesn't require a second query.
Something like INSERT INTO questions (id, position) values (0, MAX(position)).
This field is not the primary key, auto_increment is of no use to this situation.
I cannot use position as the key, because the key relates to many other things, and the position can be changed at any time.
I am a pretty confident MySQL query writer, so please don't offer any suggestions other than the question asked - I know of plenty of alternatives, this is just a syntax question.
I'm sure you get my drift!
Cheers.
Use auto_increment like most other folk do?
This is the intelligent way because it concurrency safe.
Best way would be to change the field properties within MySQL, meaning let MySql do the work without providing input.
TABLE TableName CHANGE position position INT( 11 ) NOT NULL AUTO_INCREMENT
Now when inserting, do not provide any values for this field.
INSERT INTO questions (var1, var2) values (val1,val2)
MySQL will automatically increment the position value. You can set current counter as well as reset if need be. This way you are not running any quarries at all.
something like this should work
INSERT INTO questions (id, position) SELECT 0, MAX(position)+1 FROM questions;
Obviously, you will need to handle the 0 value, as in set it for something appropriate, i just copied that value off your example.
You could also create a stored procedure to use in the query, or even have a trigger which determines the MAX(position), adds one and stores it in your newly created row.
Quite alot of options there, I would go for the above solution though (with a index on position)
There's no way to set a default value to a specific calculation, it seems.

How to mark posts as edited?

I would like to have questions marked as "Edited", but I dont know what the best way to do this would be.
Users post a question, people answer/comment on the question, and if necessary the user edits/updates the question (just like SO). I would like to note that the user edited the question, but I'm not sure of the best way to do this.
I was going to add a last_edited column in the table (because thats all thats really important to me), but I'm not sure if I should just split the edit times (and whatever else) into another table and record everytime the question gets edited.
EDIT: UIf I were to use a timestamp, what time would be used? Is there any way to insert a unix timestmap on update?
This depends on whether anyone (users or admins) ever cares about history of edits.
If they do, definitely split into another table
If all what you want is a mark Edited or not, you can just add a Timestamp column in the same table, populated to NULL by default, then populated by last update timestamp.
On the page if its populated then display its value, otherwise don't display the Edited icon/symbol.
If you only care about when the most recent update occurred, add a timestamp column in the same table.
If you'd like to keep track of every edit that's occurred, create a separate table that contains question_id and the timestamp.
Depending on how you're processing your date/time data, you can either store the unix time stamp (fieldname = unix_timestamp(now())), or as a regular mysql datetime field (fieldname=now()).
If you're going to do data sorting/filtering based on dates/times in mysql, then use the native datetime type so you can take direct advantage of all of mysql's date&time processing functions. If you're going to do most of the processing in your application, a unix timestamp tends to be more portable than a formatted date/time string.
As for the table structure, the simplest way to track edits is a pair of fields (lastedited, and lasteditor). If you want to keep a full list of editors and times, then you'll need a seperate table. If you're keeping track of the changes, then the versioning/trakcing information can go into the same table.