I am using redbeanphp 4.3 and struggling to understand why a mysql-db-trigger does not get triggered (or may be ignored).
When I work directly in the database (with phpmyadmin) and insert a row in table B, a column in table A gets updated.
When I work indrectly with the database (via a rest-api and therefore with redbean php), the row is inserted as well in table B, but the column in table A does not get updated.
This exact same behaviour I found in my android application with sugarorm too.
I then reasoned, that using an ORM ignores the usage of triggers. But so far I did not find any statement support my thesis, not in some forums, the redbean documentation nor in the rd.php source code.
An explanation or any help would be appreciated.
Thanks in advance.
Edit 1:
A script using mysqli and pdo-driver does result in the same behaviour as manual insertion (the column gets updated). Therefore PDO can not be the reason.
Solution:
Table A and B have an 1:N relation.
The problem was a misuse of redbean's R::store() method. The object1 of table A was loaded, an object2 of table B was inserted (by R::store()), the trigger was executed, but the object1 of table A did not recognize it. A final R::store() on object1 has overwritten the background updates to the initial state.
So the solution is quite simple: removing R::store() on objects of table B.
When R::store() is called on object1 of table A, it first updates entity A and inserts entity B afterwards, which will trigger the update of object1.
Try to debug the sql querys created by redBean and check if there is a column update or something else after your insert.
Configure redBean to log sql querys:
R::debug( TRUE, 3 );
Access and print the log:
$logs = R::getDatabaseAdapter()->getDatabase()->getLogger()->getLogs();
print_r( $logs );
You will find more information about debugging redBean on their official site.
Related
I've been struggling with this problem for a while now and can't figure out reasonable explanation for this behaviour...
I have in MySQL a table called "notifications" and columns "package_id", "mail_sent_at" and "sms_sent_at", and appropriate Propel model for that.
I'm setting "sms_sent_at" column with current time and saving it. Works perfectly.
$not = new Notification();
$not->setPackageId($package_id);
$not->setSmsSendedAt(time())->save();
The result for this is:
Now I want to add one more thing - set mail_sent_at column. So what I do:
$not = new Notification();
$not->setPackageId($package_id1);
$not->setMailSendedAt(time())->save();
$not->setSmsSendedAt(time())->save();
And here's the magic: only mail_sent_at column was set.
Additional notes:
after var_dump'ing i can see that dumped object has both properties set after executing these operations
var_dump'ing object retrieved from propel query by package_id after these operations executed doesn't have the second column set. As it is in DB.
Same behaviour happens other way around if I first set different column - first saved column goes into DB, second don't.
Why is that happening and how can I fix it?
Ps. Yeah, I know it's "sent", not "sended"
EDIT
Finally I found the solution. In case someone is having similar problem:
check if your primary key in propel schema has autoIncrement="true". If not - add it!
What was happening was: I've created a new object with id=null, saved it to DB using implicitly SQL INSERT (since it's new record ) and while working on the same object modified it and saved it to DB once again, but this time imlpicitly by SQL UPDATE (Propel figures out that I inserted this object once). The problem was, that after first saving I didn't get id for my object set (even though there was ID set in DB). So second SQL contained "UPDATE...WHERE id = NULL".
I'm still new and some of the right coding practices escape me. Documentation on this particular situation is weak, so I would like to get some advice/suggestions from you experts :) on the following.
I have an API that allows users to update 2 tables in one call. One is a SUMMARY table and the other is a DETAIL table with an FK to the SUMMARY table.
What I have my code doing is I do an UPSERT (insert/update) to the SUMMARY table, grab the insert_id and then delete the records from the DETAIL table, then insert the ones I need (referencing SUMMARY with the fk of course).
However, in the instance that there are no changes to SUMMARY data - insert_id returns 0. This seems expected as no row was updated/inserted.
So here is my question:
Should I be doing a full read of the tables and comparing data prior to this update/delete/insert attempt? Or is there another nifty way of grabbing the id of the SUMMARY that was a duplicate of the UPSERT attempt? I feel that my users will 'almost' ALWAYS be changing the SUMMARY and DETAIL data when using this API.
What is the correct coding practice here? Is the extra read worth it every time? Or should I read only if insert_id = 0?
Thoughts? My biggest problem is that I don't know what the magnitude difference of a read vs a write is here - especially since I don't believe the API will be called much without having changed values.
Again my options are:
Read db and compare to see if there is a diff
Insert/Update accordingly
Attempt Insert/update.
if (insert_id = 0) then read db to get summary id for details table
copmlete process
Attempt Insert/Update
use ?something? to get id of summary of record that was duplicate (and prevented insert/update)
use the id to complete steps.
If the id you need is an auto_increment field, option 4 (do everything inside DB with 1 execute action) 100% of the time. This is the general SQL structure you need:
Insert into summary (primaryKey, fieldA, fieldB) values (NULL, valueA, valueB) on duplicate key update primaryKey=LAST_INSERT_ID(primaryKey), fieldA = fieldA, fieldB=fieldB;
If you then do SELECT LAST_INSERT_ID() it'll give you either the successful inserted id or ,if duplicate, the duplicate entrie's id. So do something like:
delete from detail where summary_id = LAST_INSERT_ID();
At the companies I've worked for, option 1 is usually the one I've seen used if you're wanting to compare record by record. This can be implemented either in a stored proc or in the code itself. Depends on the context of what "same" means. If it's raw values, then sql is probably the easiest. If there's a context in addition to what the database has, you'll want to do it at the code level. Hope that helps.
i have 2 sql tables of a script that i need to be sync to another, this can be done with php cron (this was my plan) exept from one row
Table 1 Table 2
row 1 <----> Row 1
Row 2 <----> row 2
row 3 no sync row 3
both databases on same server
and the same user has full rights for both
i am looking for a php code to do this via a cpanel cron
on an after thought would it be best to merge the two so both updates with new data?
the issue is that in the example above i am needing row 3 to not change on both databases
I am very noob so please be nice lol Thx in advance
Update *
i should learn how to explain a bit better.
both the databases are control panels for sites, one of the tables rows has the system url in it, so if i share the database "site 2" links refers back to "site 1" this is a complex problem for me as i am very new to this.
what i need is to keep both databases upto date except that single row which in turn be different for both databases.
i have not tried anything just yet as i wouldn't know where to start :( lol
You dont have to use cron. MySQL in current version supports TRIGGERS and EVENTS.
You can use TRIGGER to copy data to another table. That copy (or any other operation) may be triggered by some event (like insert, update or delete in table). TRIGGER may run any query or any PL/SQL code.
Other option is an EVENT. This is something like internal task sheduler built in MySQL. It can also run queries, or any PL/SQL code, but it is triggered by system time (like Linux Cron). It has many advantages compared to cron.
PL/SQL is procedural SQL, with loops, variables and more.
If you think you are "noob" - i have cure for you. Read books about MySQL or if you are lazy - watch some tutorials ( http://thenewboston.org , http://phpacademy.org ).
Nobody here will write code for you. We can only fix a bug, give advice etc. :)
EDIT.
Example of EVENT:
-- this is comment in SQL language (line starts with --)
CREATE EVENT event_daily_copy_something
ON SCHEDULE
EVERY 1 DAY
COMMENT 'This text will appear in MySQL Workbench as description of event'
DO
BEGIN
INSERT INTO your_db_name.target_table_name(id, field)
SELECT id, something
FROM your_db_name.source_table_name
WHERE id = 3;
END
Synchronization of tables is quite complicated. I think you need few operations in event.
Check for new rows and copy
Check for deleted rows and delete them in "copy" table
Check for changed rows (here trigger on source table would be very useful, because trigger "knows" what row is edited and you can access new field values in table 1 and use them to update table 2).
One of MySQL tutorials - thenewboston#youtube.
EDIT: This question title originally was: How does Doctrine know last inserted id in MySQL? and was related to Doctrine ORM mapper. After some digging I found out that this question is not related to Doctrine but to PDO_MySQL, MySQL C API and finally - to MySQL client-server communication. I have decided to change the title, so maybe someone will find answer to his/hers question.
For those who are not using Doctrine: I was curious, why bellow:
mysql_query("INSERT INTO category (name) VALUES('cat')");
echo mysql_insert_id();
or similar:
$pdo->exec("INSERT INTO category (name) VALUES('cat')");
echo $pdo->lastInsertId();
will lead to only one position (without separate SELECT LAST_INSERT_ID()) in log:
1701 Query INSERT INTO category (name) VALUES ('cat')
Original question:
I have 2 tables:
category(id,name)
product(id, name, categoryId)
I created new category object and product object. I assigned category object to product object. I didn't set any ids:
$product = new Product();
$product->name = 'asdf';
$category = new Category();
$category->name = 'cat';
$product->Category = $category;
After that I flushed the connection and check MySQL logs:
1684 Query START TRANSACTION
1684 Query INSERT INTO category (name) VALUES ('cat')
1684 Query INSERT INTO product (name, categoryid) VALUES ('asdf', '312')
1684 Query COMMIT
How did Doctrine know, that the newly created category id is 312? There is nothing else in logs.
I did some research and browse some source code, so my answer could be a little bit wrong and not precise.
First of all, this is not really related to Doctrine. Doctrine uses PDO_MYSQL. But internally PDO_MYSQL uses the same thing as mysql_insert_id function - native MySQL C API function - mysql_insert_id.
The reason why there is no seperate SELECT LAST_INSERT_ID() lies in the fact, that after the statement is executed (in my example INSERT), server responds with data and some other things included in OK Packet), including insert_id. So when we fire mysql_insert_id() we are not connecting to the server, to receive insert_id - mysql library does not need to do that - it already has this value stored from last execution of query (at least I think so after analyzing the file libmysql.c)
OK Packet is described here: MySQL Generic Response Packets - OK Packet
Probably by calling http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
last_insert_id works only for AUTO_INCREMENT columns. It will not work if you insert a value manually into the AUTO_INCREMENT column.
The doctrine will work because it is just like assigning a NULL to it (although you never specifically write that). This triggers the auto increment and provide a value for last_insert_id().
I have included a jpg here so that you can see it. Hope it helps!
I have the following. Two mysql tables. I want to copy info that has changed from table a to b.
For example if row 1 column 2 has changed in table a I want to only update that column in table b. Table b is not the same as a but has same columns that also exist in a. The other solution I have is to just clear table b and replace it with the contents from table a, the problem with this could be that the script will take longer to execute, since there are more than 10000 records. Any advise for which method would work the best will be highly appreciated
use trigger on update one table that update another.
can see example in this tutorial
http://www.brainbell.com/tutorials/MySQL/Creating_Triggers.htm
and in this post
http://forums.mysql.com/read.php?99,282455,282559#msg-282559
If you've got the same data in 2 different tables on the same database, then your database is not normalized - you're just compounding your difficulties by finding workarounds for the bad structure.
If these were 2 seperate databases - say distributed nodes on a cluster (although this implies bi-directional synchronization) or where you have an near-online copy of the database for reporting purposes, then you should still normalize your data properly and move the fields not present in table 'a' but found in table 'b' to a third table. The to address the population/replication issue, either:
1) use the builtin replication functionality in MySQL
2) add an indexed timestamp field to table 'a' then merge the records that have been updated since some time T
Note that the second method doesn't propogate deletions.
C.