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
Related
Example tables (not actual database):
In this example, I would have the SecurityCode(Unique), and Time. My current solution involves attempting to add a new Person using the security code, then querying the ID, then adding to the Times table. This is 3 separate statements and could likely be a lot faster. Any advice on how to optimise this?
Thanks.
Edit: I previously forgot to mention that this is normally done in a batch of 30-40 records.
I am also considering using SecurityCode as the foreign key in Times.
I think there are many ways of achieve this, the easiest:
Try using "IF", you only need it for the first step of your statement, the last two are independent to the result of this evaluation.
Plus, save your security code in a variable, then you will save one table scan (you already have it)
**please note its just pseudo-code**
IF (exists select * from person where securityCode = #securityCode) then
Step 1
End
Step 2
Step 3
Can you try it?
The fastest way seemed to be to batch ignore insert all security codes, then batch insert all Times with a subquery to select the correct ID from Person.
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'))
I have a food_table and a person_table. Then I have a third table fav_food_table that stores the relation between food and person using food_id and person_id.
When the person goes to account info and updates his favourite food, the input data is passed to the PHP (HTTP) script as an array of selected food_id. A person can have multiple fav_food, the relation is one-to-many.
The naïve way to update fav_food_table is to delete from fav_food_table all that belongs to person_id then re-insert all the rows again. Thus, using 2 statements.
Is there a single statement that can do the same thing?
PSUEDO CODE:
CREATE TABLE food_table (food_id, food_name);
CREATE TABLE person_table (person_id, person_name);
CREATE TABLE fav_food (person_id, food_id);
You have a m:n relationship between person_table and food_table. This means you have multiple records in your relationship table related to the same person. When a person updates their favourite foods, any combination of four independent cases can occur:
Food A was favourite before, but is not anymore (DELETE FROM fav_food_table)
Food B was favourite before and still is! (do nothing)
Food C was no favourite before, but now is a favourite (INSERT INTO fav_food_table)
Food D was no favourite before, and still is no favourite! (do nothing)
To correctly keep your database up to date, you have to handle all four cases. Cases 2 and 4 are covered easily. Just don't do anything :)
That means, you have to do at least two steps to keep your database up to date: 1 and 3.
Your goal seems to be to reduce the number of sql statements, that have to be executed.
Deleting all favourites for one person from the table can always be done with a single statement:
DELETE
FROM fav_food_table
WHERE person_id = ?;
To delete selected favourites for one person, only an AND food_id IN (?,?,?) has to be added to the WHERE clause.
Inserting into the table can also be done with a single statement:
INSERT INTO fav_food_table (person_id,food_id)
VALUES (?,?),
(?,?),
(?,?),
.....;
Summary as of right now:
No matter, whether we delete all old records for this person and then insert all new records, or whether we only delete selected records and insert new ones: We can do it with two statements!
In the second case (the "smart" case), however, we need to know not only the new state of the relation, but also the old state to compute the difference between the two. This will result in either one more SELECT statement or needs some smart "client" (PHP) logic.
Your two step process doesn't seem to be naive, but easy and effective to me. There is no way to reduce this process to less than two statements.
If you want to reduce the number of times you have to effectively send commands from PHP to the server, you can either look into mysqli_multi_query() or into creating a stored procedure which holds both your DELETE and INSERT statement. But bottom line, this will be the same thing as executing the two queries on its own.
You can also look into MySQL Transactions to implement a safer process and be able to rollback your DELETE command should an error occur later on.
May I suggest something different. Instead of deleting, updating?
Deleting data in common is something that should be thought off. Deleting data cannot be retrieved. So check this out.
We are adjusting your code a bit.
CREATE TABLE food_table (food_id, food_name);
CREATE TABLE person_table (person_id, person_name);
CREATE TABLE fav_food (person_id, food_id, fav_food_active);
/* see the last column i added. It should be a bit type and can only hold the values 0 and 1. */
Now you technically can update this everytime. No need for deleting the values. This statement is
/* deletion */
UPDATE Fav_Food
SET fav_food_active = 0
WHERE food_id = (your food_id)
AND person_id = (your person_id)
/* activating it again */
UPDATE Fav_Food
SET fav_food_active = 1
WHERE food_id = (your food_id)
AND person_id = (your person_id)
So now you switch between those 2 for activating and deleting it, without having the consequences of deleting hard data. Overal, you can just call it like this in your code
SELECT *
FROM fav_food
WHERE (here your where clause on which you wanna search for)
AND fav_food_active = 1
Remember when you enter something in the database, you should always add it as 1. You can do that in PHP myadmin as auto value, or hard code it in your INSERT statement.
I am not sure what your backend code is (okay taking that back, its PHP, i read your post) looking at your question you shooting everything through an array, but try to work in some checks that foreach fav_food entry, check first in the db if the query excists. If it does, update it, if not, insert it. and let that run in a loop.
So something like
foreach ($food_id as $value){
// check here the overal statement if it excists in your db
// give back count
if ($count == 1){
// update query to delete it.
}else{
// create your insert query here
}
}
Hope this helps. Happy coding!
I am looking for a (not too convoluted) solution for a MySQL problem. Say I have the following table (with a joint index on group and item):
Group item
nogroup item_a
group_a item_a
Then, eventually, item_a no longer belongs to group_a. So I want to do something like:
update table set group = "nogroup" where item = "item_a" on duplicate key delete.
(obviously this is not a valid symtax but I am looking for a way around this)
I still want to keep a copy of the record with nogroup because, if later on, item_a comes back, i can change its group back to group_a or any other group depending on the case. Whenever item_a is added, there is an insert and it copies all the data from the nogroup record and sets a proper group label. At that point there are two records for item_a: one with group_a and one with no group. The reason it is done this way is to reuse previous data as much as possible as a new entry(with no previous record) is much more involved and take significantly more time and processing.
Say an item belongs to group_a and group_b but suddenly it does not belong to any group: the first update to set group to "nogroup" will work but the second update will create a duplicate key entry error.
The option of "not updating the group column at all" and using "insert on duplicate key update" does not work because there won't be duplicates when the groups are different and this will lead to cases where an item does not belong to a group anymore and yet the record will still be present in the database. The option of verifying if "nogroup" exists first and then updating it to a specific group does not work either because if item_a belongs to more than one group this would update all other records to the same group.
Basically, an item can belong to 1) any number of groups including "nogroup" or 2) solely belonging to "nogroup" and there should always be a copy of at least nogroup somewhere in the database.
It looks like I won't be able to do this in just one query but if someone has a clean way of dealing with this, that would be much appreciated. Maybe some of my assumptions above are wrong and there is an easy way to do it.
Your whole process of maintaining this items-to-groups mapping sounds too complicated. Why not just have a table that has a mapping? Then, when an item is removed from a group, delete it from the table. When it is added, add it to the table. Don't bother with "nogroup".
If you want an archive table, then create one. Have an insert/update/delete trigger (whichever is or are appropriate) that will populate an archive with information that you want to keep over time.
I do not understand why re-using an existing row would be beneficial in terms of performance. There is no obvious database reason why this would be the case.
I am also confused as to why you need a "nogroup" tag at all. If you need a list of items, maintain that list in its own table. And call the table Items -- a much clearer name than "nogroup".
I agree with Gordan's approach. However if you have to do it with a single table it cannot be done in 1 SQL query. You will have to use 2 queries 1 for update and 1 for delete.
I would like to store random numbers in one MySql table, randomly retrieve one and insert it into another table column each time a new record is created. I want to delete the retrieved number from the random number table as it is used.
The random numbers are 3 digit, there are 900 of them.
I have read several posts here that describe the problems using unique random numbers and triggering their insertion. I want to use this method as it seems to be reliable while generating few problems.
Can anyone here give me an example of a sql query that will accomplish the above? (If sql query is not the recommended way to do this please feel free to recommend a better method.)
Thank you for any help you can give.
I put together the two suggestions here and tried this trigger and query:
CREATE TRIGGER rand_num before
INSERT ON uau3h_users FOR EACH ROW
insert into uau3h_users (member_number)
select random_number from uau3h_rand900
where random_number not in (select member_number from uau3h_users)
order by random_number
limit 1
But it seems that there is already a trigger attached to that table so the new one cause a conflict, things stopped working until I removed it. Any ideas about how accomplish the same using another method?
You are only dealing with 900 records, so performance is not a major issue.
If you are doing a single insert into a table, you can do something like the following:
insert into t(rand)
select rand
from rand900
where rand not in (select rand from t)
order by rand()
limit 1
In other words, you don't have to continually delete from one table and move to the other. You can just choose to insert values that don't already exist. If performance is a concern, then indexes will help in this case.
More than likely you need to take a look into Triggers. You can do some stuff for instance after inserting a record in a table. Refer this link to more details.
http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html