Is it possible to insert a row into multiple tables at once? If you do several tables related by an ID; what is the best way to ensure integrity is maintained in case an INSERT fails?
That's exactly what transactions are for. If any of the commands fail, the whole thing since START TRANSACTION is rolled back:
START TRANSACTION;
INSERT INTO sometable VALUES(NULL,'foo','bar');
INSERT INTO someothertable VALUES (LAST_INSERT_ID(),'baz');
COMMIT;
This being MySQL, you can't use transactions with MyISAM tables (you'll need the tables to use some engine that supports this, probably InnoDB).
This will never be inserted into the table (normally you'd have some branching, e.g. an IF):
START TRANSACTION;
INSERT INTO sometable VALUES(NULL,'data','somemoredata');
ROLLBACK;
Caveat: SQL commands which change the database structure (e.g. CREATE,ALTER,DROP) cannot be rolled back!
Use transactions, luke.
MySQL can insert multiple rows (search for 'multiple rows') like this:
INSERT INTO table (field1, field2, ...) VALUES (value1, value2), (value3, value4), etc...
However, there's no way to tell what got inserted and what wasn't due to constraint violations, beyond the query returning a count of records, duplicates, and warnings. You also can't use last_insert_id() to figure out the IDs of the new rows, as that only returns the LAST id that was created, not a set of ids.
If you need to guarantee integrity, then use single row insert statements and transactions.
Related
I have a database with multiple tables, in al the tables there have to be a row because else my query is going wrong. In one of my insert pages i insert al the rows seperatly in the tables. Is there a more efficient and safe way to do this? Maybe in Mysql (CASCADE)?
afaik there is no other way to same data into different tables in same statement.
But you can try using transactions.
START TRANSACTION;
insert into t1 (field1, field2) values ('data1','data2');
After inserting the data you can check them if they are ok and if everything is like expected than commit your queries:
COMMIT;
or do a rollback, which removes the changes sience "START TRANSACTION".
ROLLBACK;
I suggest using a MySQL Transaction, which allows you to rollback the inserts if one of them fails. SQL to start the transaction:
START TRANSACTION;
At this point, do your inserts, if one of them errors then rollback:
ROLLBACK;
If all of the inserts complete with no errors, you can commit your inserts:
COMMIT;
MySQL docs for transactions
I am using InnoDB in MySQL and accessing the table from PHP with PDO.
I need to lock the table, do a select and then, depending on the result of that either insert a row or not. Since I want to have the table locked for as short a time as possible, can I do it like this?
prepare select
prepare insert
begin transaction
lock table
execute select
if reservation time is available then execute insert
unlock table
commit
Or do the prepares have to be inside the transaction? Or do they have to be after the lock?
Should the transaction only include the insert, or does that make any difference?
beginTransaction turns off autocommit mode, so it only affects queries that actually commit changes. This means that prepared statements, SELECT, and even LOCK TABLES are not affected by transactions at all. In fact, if you're only doing a single INSERT there's no need to even use a transaction; you would only need to use them if you wanted to do multiple write queries atomically.
I have the following PHP code:
$dbh->beginTransaction();
$dbh->exec("LOCK TABLES
`reservations` WRITE, `settings` WRITE");
$dbh->exec("CREATE TEMPORARY TABLE
temp_reservations
SELECT * FROM reservations");
$dbh->exec("ALTER TABLE
`temp_reservations`
ADD INDEX ( conf_num ) ; ");
// [...Other stuff here with temp_reservations...]
$dbh->exec("DELETE QUICK FROM `reservations`");
$dbh->exec("OPTIMIZE TABLE `reservations`");
$dbh->exec("INSERT INTO `reservations` SELECT * FROM temp_reservations");
var_dump(GlobalContainer::$dbh->inTransaction()); // true
$dbh->exec("UNLOCK TABLES");
$dbh->rollBack();
Transactions are working fine for regular updates/inserts but the above code for some reason is not. When an error happens above, I'm left with a completely empty reservations table. I read on the PDO::beginTransaction page that "some databases, including MySQL, automatically issue an implicit COMMIT when a database definition language (DDL) statement such as DROP TABLE or CREATE TABLE is issued within a transaction". The MySQL manual has a list of "Data Definition Statements", which I would assume is the same as DDL mentioned above which lists CREATE TABLE but I am only creating a temporary table. Is there any way around this?
Also, does the fact that I'm left with an empty reservations table show that a commit occurred after the DELETE QUICK FROM reservations query?
Edit: On an additional note, the INSERT INTO reservations line also produces the following error:
Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
I tried doing $dbh->setAttribute( PDO::MYSQL_ATTR_USE_BUFFERED_QUERY , true); but this doesn't seem to affect it. I'm assuming it would have something to do with the transaction, but I'm not sure. Can anyone pinpoint what exactly is causing this error as well?
Your OPTIMIZE TABLE statement is causing an implicit commit.
I'm not sure exactly what you're trying to do, but it looks you can shorten your code to:
$dbh->exec("OPTIMIZE TABLE `reservations`");
All the other code is just making the job more complex, for no gain.
I'm also assuming you're using InnoDB tables, because MyISAM tables wouldn't support transactions anyway. Every DDL or DML operation on a MyISAM table implicitly commits immediately.
By the way, buffered queries have nothing to do with transactions. They have to do with fetching SELECT result sets one row at a time, versus fetching the whole result set into memory in PHP, then iterating through it. See explanation at: http://php.net/manual/en/mysqlinfo.concepts.buffering.php
I have only just begun learning about joining tables in MySQL. Now, I have a small project where I simply want to let the visitor insert data through a form. The data is then displayed in a HTML table with four rows, joining together two tables in my database. The "problem" is that the data should be submitted into those two different tables in my database.
I tried
$query = "INSERT INTO table1, table2 (col1, col2, col3, col4) VALUES ('value1', 'value2', 'value3', 'value4')";
but that doesn't seem to do it. What is the correct syntax for submitting form data to several database tables? Oh, and I read some similar threads mentioning using transactions. Is this necessary? My tables are run with MyISAM. Thanks!
You can read more about it from the MySQL Manual. In short, you cannot insert into multiple tables at once. This leaves you with three options:
Multiple INSERT statements
Triggers
Stored Procedures
The answer to this question: MySQL Insert into multiple tables? (Database normalization?) suggests using transactions, which will not work with MyISAM, but is a good FYI if you ever switch to InnoDB.
I really recommend you read up on Triggers. They can make your life a lot easier. But if you don't want to use them, look into PHP's mysqli_multi_query, which will allow you to execute two different queries at the same time, for example:
$query = "INSERT INTO table1 (col1,col2) VALUES ('$value1','$value2');";
$query = "INSERT INTO table2 (col3,col4) VALUES ('$value3','$value4');";
$result = mysqli_multi_query($dbcon, $query);
You can perform this by using MySQL Transactions By:
Try:
BEGIN
INSERT INTO table1 (col1, col2...ETC)
VALUES('value1', 'value2'...ETC)
INSERT INTO table2 (col1, col2...ETC)
VALUES('value1', 'value2'...ETC);
COMMIT;
With MyISM you will need to execute the query for each table you want to insert into, I do not believe that in a single query you can add to multiple tables.
In your case you can not use Transactions because they are not supported by your engine.
Your only solution is to use several separate queries, preferably within a transaction. Transactions are necessary if you want to make sure that the data from each query is inserted, in which case you COMMIT the transaction; should one of the queries fail, you can ROLLBACK.
P.S. Use InnoDB. It's better in pretty much any environment where INSERT queries make up at least 5% of all queries (sadly I cannot give the source as I had read it several months ago and no longer remember where).
I may be wrong, but you don't insert into multiple tables at the same time. You split it into two or more commands, each handling the specific insertion, whats the big deal, that one extra line of code (which makes everything clearer) too much of a hassle to type?
Look at it this way, if you write a large script, for instance a routine to process some data, the more you segment the code, the easier it is to debug, and, if necessary, inoculate instructions that are problematic, it will end up saving you time in the long run.
I have this problem before You can use multiple query function
$query = "INSERT INTO table1 (col1,col2) VALUES ('$value1','$value2')";
$query = "INSERT INTO table2 (col3,col4) VALUES ('$value3','$value4')";
$result = mysqli_multi_query($dbcon, $query);
I got two tables. One is account, another is Interest.
One account can have multi Interests and It can be edited.
Now, the process is deleting all Interest of this account then insert these insterests.
The QUERY IS:
"DELETE FROM Interests WHERE account_id='$id'"
"INSERT INTO Interests (account_id, interest_name) VALUES('$id', '$name')"
I use the both query when user update their account, but the insert is fail, there is nothing insert into the table (ps. the interests_id is auto_increment and this was be counted) but there is nothing new in the table. When I comment out the delete query. The insert will be successful.
Does any one know what can i do?
If you want to update your table records, you will do update operation.
like this:
UPDATE TABLE_NAME SET FIELD_NAME = 'VARIABLE_NAME'
WHERE PRIMERY_FIELD_NAME = 'VARIABLE_NAME' ;
you did not have to use these two queries, if you want to update data simply use the updat query of mysql.use this:
<?php
$query = "UPDATE Interests SET interest_name = '".$name."' WHERE account_id = '".$id."'" ;
mysql_query($query);
?>
If you want to update your table records then you may execute update operation. It like following
UPDATE Interests
SET
interest_name = '$name'
WHERE
accountno = '$id' ;
Try it. You may solve your problem by this way.
If you have queries failing, you should capture the error and see what went wrong. In all MySQL APIs for PHP, a query that fails returns a status code to indicate this. Examples of checking this status code are easy to find in the docs. But most developers fail to check the status.
Use transactions to ensure that both changes succeed together or neither are applied.
How to Decide to use Database Transactions
Definition of a transaction in MySQL: http://dev.mysql.com/doc/refman/5.5/en/glossary.html#glos_transaction
Syntax for starting and committing transactions in MySQL: http://dev.mysql.com/doc/refman/5.5/en/commit.html
You need to use InnoDB. MyISAM does not support transactions. http://dev.mysql.com/doc/refman/5.5/en/innodb-storage-engine.html
In PHP, you need to stop using the old ext/mysql API and start using MySQLi or PDO.
http://php.net/manual/en/mysqli.quickstart.transactions.php
http://php.net/manual/en/pdo.begintransaction.php
This happens because the query are treated as two single transaction, so the order of execution is not guaranteed.
The effect you are describing is because the insert is processed before delete, so the interests_id is auto-incremented properly, then the row is deleted by delete statement.
You should change the query logic or perform both queries in one single transaction.