Multiple MySQL queries (no PHP) - mysql

I am wondering if it is possible to perform a SQL query then update another table with the generated ID and continue through all of the rows?
I have this SQL query that works but what I need to do is after each row is added to cards to then update merged.cars_id with the last generated ID so they are linked. normally I would do this with PHP but ideally I would like to just do it with MySQL if possible.
MAIN QUERY
INSERT INTO cards (first_contact_date, card_type, property_id, user_id)
SELECT first_contact_date, 'P', property_id, user_id FROM merged
THEN I NEED WITH MATCHING ROWS (Roughly)
UPDATE merged SET merged.card_id = LAST_INSERT_ID (FROM ABOVE) into the matching record..
Is something like this possible and how do I do it?

I would recommend using MySQL triggers to do this
http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html
A trigger is a function that will be executed AFTER or BEFORE the INSERT or DELETE or UPDATE is done over any record of your table.
In your case you need to do a AFTER INSERT on cards that just updates the merged table. Make sure its AFTER insert as you wont be able to access the new row's ID otherwise.
The code would look something like this, assuming the id field from the cards table its named "id"
delimiter |
CREATE TRIGGER updating_merged AFTER INSERT ON cards
FOR EACH ROW BEGIN
UPDATE merged SET card_id = NEW.id;
END;
|
delimiter ;

May I suggest Stored Procedures?
http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html
--EDIT--
Ah yes, triggers. For this particular situation, Jimmy has the answer. I will leave this post for the sake of the link.

I would set up a trigger to do this. For mysql, read http://dev.mysql.com/doc/refman/5.0/en/triggers.html. This is what triggers are designed to handle.

Related

Trigger Preventing Record Insertion

I was trying to create trigger which can update value of column user_count of table user_details using value of u_count of table user_info.
CREATE TRIGGER `test`
AFTER INSERT ON `user_details` FOR EACH ROW
BEGIN
DECLARE default_user_count int(11);
SELECT u_count INTO #default_user_count FROM
user_info WHERE user_info.id= user_details.id_c;
IF user_details.user_count= 0
THEN UPDATE user_details SET
user_count = default_user_count
WHERE user_details.id_c = user_info.id;
END IF;
END
Trigger saved successfully but when i tried to insert value in both table it is preventing to insert record into user_details means no row inserted in 2 this table, if we delete trigger then its working.
Can anyone let me know wrong with this trigger?
THanks,
M.
It's not really clear what you're trying to accomplish, but it seems like it's something like what we have below.
There are numerous errors in and ambiguities in your trigger.
Confusion on variables -- DECLARE default_user_count INT(11); does not declare the user-defined variable #default_user_count. It declares the program variable default_user_count. The # prefix references an entirely different variable scope and namespace.
SELECT and UPDATE from the table which invoked the trigger doesn't usually make sense (SELECT) or is completely invalid (UPDATE).
With in a trigger, you are operating FOR EACH ROW -- that is, for each row included in the statement that invoked the trigger. Inside an INSERT trigger, the NEW values for the row are in a pseudo-table/pseudo-row accessible via the alias NEW. For UPDATE triggers, there are NEW and OLD row values, and for DELETE triggers, just OLD.
AFTER INSERT doesn't seem to make sense. I think you're looking for BEFORE INSERT -- that is, while processing an INSERT INTO ... query, before the newly-inserted row actually gets written into the table, modify its values accordingly. The resulting row contains the original values except where the trigger has modified them.
SELECT ... INTO a variable is a practice you should not get into the habit of, because it can bite you in a way a scalar subquery can't, by leaving a variable unexpectedly unaltered instead of setting it to NULL as would be expected. In this case, it would have made no difference, but it's still a caution worth mentioning... and in this case, I've eliminated that intermediate variable altogether, so the subquery is the only option.
If you are trying to set a value in this table using a value found in another table, all you need to do is SET NEW.column_name equal to the value you want used in the row instead of the value provided with the insert statement.
CREATE TRIGGER `test`
BEFORE INSERT ON `user_details` FOR EACH ROW
BEGIN
IF NEW.user_count = 0 /* maybe also >> */ OR NEW.user_count IS NULL /* << this */ THEN
SET NEW.user_count = (SELECT ui.u_count
FROM user_info ui
WHERE ui.id = NEW.id_c);
END IF;
END
Again, it's unclear how the two tables are connected based on the content of the original question, but this appears to do what you're trying to accomplish.

insert ... select ... on duplicate key update + delete obsolete rows

I need to update a table with pre-calculated values from tables where data can be added/updated/deleted.
I could use
insert into precalculated(...)
select ... from ...
on duplicate key update ...
to add/update the pre-calculated table but is there an optimized method to delete the obsolete rows ?
I think you should create a stored procedure that deletes the data of your related tables if and only if the records fulfill a condition.
There's not enough information in your question to design the procedure, but I can give you a little example:
delimiter $$
create procedure delete_orphans()
begin
declare id_orphan int;
declare done int default false;
declare cur_orphans cursor for
select distinct d.id
from data as d
left join precalculated as p on d.id = p.id
where p.id is null;
declare continue handler for not found set done = true;
open cur_orphans;
loop_delete_orphans: loop
fetch cur_orphans into id_orphan;
if done then
leave cur_orphans;
end if;
delete from data where id = id_orphan;
end loop;
close cur_orphans;
end$$
delimiter ;
This procedure will delete every row in the data table that does not have at least one related row in the precalculated table.
Of course, this approach might be inneficient, because it will delete the rows one by one, but as I said this is only an example. You can customize it to fit your needs.
You can call this procedure from a trigger if you want (with call delete_orphans()).
Hope this helps.
Since you are always adding or updating rows that exist in these other tables, and you want to remove any rows that don't exist, why don't you just :
DELETE FROM precalculated
insert into precalculated(...)
select ... from ...
on duplicate key update ...
Always starting clean means you don't have to worry about orphans later.
You could add triggers for insert, delete and update on the main tables that maintains precalculated.
When inserting or updating the same code can be used to calculate the values and issuing a replace into precalculated (...) values (...)
When deleting it's probably the same, with the addition that you'll also delete rows from precalculated that are orphans. Be smart here and use values from the original delete to query precalculated for orphans instead of doing a table scan.
I may have found my solution using rename.
so basically, I will do a simple insert select to the temporary table and then
rename precalculated to precalculated_temprename, precalculated_temp to precalculated, precalculated_temprename to precalculated_temp;
truncate precalculated_temp;
need some tests but it seems the rename operation is fast and atomic.

Identifying the edited columns in the database

At the beginning the application have an admins and employees and records.
The records table has many columns than can be changed by any employee. However, this change can not be submitted. When the admin approve for an edit the record will show up again in the system.
I was trying to identify the column name and the value, and send it to another table using triggers on UPDATE.
So when the employee edits any record, the record will be disabled in the system. Also the admin will be able to know which values has been changed.
Is this possible in databases ?
Records Table
-------------------------------------------------------------------
record_id record_name record_serial record_active
-------------------------------------------------------------------
1 something 5151 YES
When an update happens to the record_serial, such as from 5151 to 9844 I need to do this.
Records_changes
-------------------------------------------------------------------
change_id record_col record_old_val record_new_val
-------------------------------------------------------------------
1 record_serial 5151 9844
At the same time
-------------------------------------------------------------------
record_id record_name record_serial record_active
-------------------------------------------------------------------
1 something 9844 NO
I can do it using my application, but if there is anyway to do it using the database it would be much nicer.
I will use this to track the changes, and also create a history for the records old values.
I am using MySQL
You can do something like this
DELIMITER $$
CREATE TRIGGER tg_bu_records
BEFORE UPDATE ON records
FOR EACH ROW
BEGIN
IF NOT (OLD.record_serial <=> NEW.record_serial AND
OLD.record_name <=> NEW.record_name) THEN
SET NEW.record_active = 0;
END IF;
END$$
CREATE TRIGGER tg_au_records
AFTER UPDATE ON records
FOR EACH ROW
BEGIN
IF NOT (OLD.record_serial <=> NEW.record_serial) THEN
INSERT INTO records_changes (record_col, record_old_val, record_new_val)
VALUES ('record_serial', OLD.record_serial, NEW.record_serial);
END IF;
IF NOT (OLD.record_name <=> NEW.record_name) THEN
INSERT INTO records_changes (record_col, record_old_val, record_new_val)
VALUES ('record_name', OLD.record_name, NEW.record_name);
END IF;
END$$
DELIMITER ;
Note: The trick is to change record_active flag in BEFORE trigger because it's the only event when you can change values of a row being updated/inserted in a table on which you defined that trigger. Now in AFTER trigger we record the changes that have been made.
Here is SQLFiddle demo
A good database pattern for this, if I understand your problem correctly, is to use versioned rows. You add columns (or additional referenced tables) with meta data about when/who/what the edit was about. When a record is edited, a new row is inserted. Previous versions are never modified or deleted. Then it's up to your application logic to decide what to do with all of this.

Create a trigger that removes a name from a table if it is present in another

To futher clarify i was trying to create a trigger that checks a table for a number in sql.
If it finds said number then it erases that entire row.
It uses a separate table of names to check.
I thought it be could done using a join but have had no luck.
So it would look like this I suppose if(tb1.name = tb2.name) then DELETE row.
I'm sorry if the formatting is off.
EDIT; I am using phpmyadmin so some of the the code may be missing but here is the code from my latest "attempt"
It uses on INSERT and time is set to AFTER
SELECT * FROM flights WHERE NOT EXISTS (SELECT * FROM no fly list WHERE PassengerId.Id = Passenger.Id)
have not added the DELETE as of now but the work is somewhat ongoing
Assuming that flight and dnf both have passenger_id column that uniquely identifies a passenger of interest then your trigger might look like this
DELIMITER $$
CREATE TRIGGER dnf_insert AFTER INSERT
ON dnf
FOR EACH ROW BEGIN
DELETE FROM flights WHERE passenger_id = NEW.passenger_id;
END$$
DELIMITER ;
If you post DDL (create table statements) for all relevant tables we can refine the query

MYSQL auto increase column entity by 1 on update?

I have a table: ID,name,count,varchar(255)
Now, what i'd like is to increase the "count" each time that row in the table is updated.
Of course, the easy way is to read first, get the value, increase by 1 in php, then update with the new value. BUT!
is there any quicker way to do it? is there a system in mysql that can do the ++ automatically? like autoincrement, but for a single entity on itself?
I see two options:
1.
Just add this logic to every update query
UPDATE `table` SET
`data` = 'new_data',
`update_counter` = `update_counter` + 1
WHERE `id` = 123
2.
Create a trigger that will do the work automatically:
CREATE TRIGGER trigger_name
AFTER UPDATE
ON `table`
FOR EACH ROW
BEGIN
UPDATE `table`
SET `update_counter` = `update_counter` + 1
WHERE `id` = NEW.id
END
Create a trigger:
http://dev.mysql.com/doc/refman/5.1/en/create-trigger.html
Triggers are pieces of code that are "triggered" by the database on certain events. In your case, the event would be an update. Many RDBMS support triggers, so does MySQL. The advantage of using a trigger is that every piece of your PHP logic that updates this entity, will implicitly invoke the trigger logic, you don't have to remember that anymore, when you want to update your entity from a different piece of PHP logic.
you can look up at the trigger
or can do with the extra mysql query
update table set count=count+1 ;
UPDATE table SET name='new value', count=count+1 WHERE id=...
An SQL update can use fields in the record being updated as a source of data for the update itself.