PDO - Multiple inserts / updates in one query - php

I wrote some code that built up a single query of multiple insert and update statements which was executed at the end of a page load. It used to work okay. I am writing similar, optimised code on my dev system (Ubuntu 14.04, PHP 5.5.3-Ubuntu), but I am no longer able to run multiple statements in one PDO query:
What I do
During a page render, I build up an SQL statement that would look a bit like:
insert into <table> (col1,col2,col3) VALUES (?,?,?);
update <table> set col1 = ?, col4 = ? where id = ?;
insert into <table> (col1,col2,col3) VALUES (?,?,?);
...
When the page has been rendered and I'm sure there are no problems, I execute the query using a wrapper for PDO. The important bits of the wrapper function are
$database = new PDO("mysql:host=<host>;dbname=<dbname>", <user>, <pwd>,
array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names 'utf8'"));
$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $database->prepare($sql);
$stmt->execute($params);
For some reason, I am no longer able to execute this statement in one hit, instead, PDO only performs the first query, despite $stmt->queryString still holding the whole query. Can anyone help me with this problem.

Found the problem:
PDO fails silently if one of the queries throws an exception. In my case, the first query was okay, but the second was throwing an integrity constraint failure error, so it looked like only the first query was being run.
A wise man just told me: Don't shoot the messenger, break the queries up

Related

Multiple query PHP Mysql [duplicate]

I want to run mysql queries to insert data from a custom html form.
Here I have to insert multiple set of data, some data to one table and some to other. Currently I am using the simple approach to send data to php page using jquery ajax and run multiple mysqli_query() functions one after another. But I guess when there will be large number of users, there will be problems related to speed. So can anyone suggest me a better way to do the same.
There are 5 tables in the database and each table has 7 to 10 columns that need to get different set of data, every time.
I want to run each query only if the previous insert query is successfully completed.
That's why I am checking for the result every time and then running the next query, which makes me feel the issue of speed on large user base.
The problem is, I need to insert data to first table and if its successfully inserted then only run query for the second table.
This means you need a transaction.
A transaction is a set of queries that either all execute ok or if one fails - they all fail. This is to ensure you don't end up with crap data in your tables.
Do not
Do not use multiquery.
Do not use mysql_* function(s).
Do not use bulk inserts.
People telling you to do that just have absolutely no clue what they're doing, ignore them.
Do
Use PDO
Use prepared statements
Prepare the statement(s) ONCE, use them MULTIPLE times
Sample code - do NOT copy paste
$dsn = 'mysql:dbname=testdb;host=127.0.0.1;charset=utf8mb4';
$user = 'dbuser';
$password = 'dbpass';
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$insert['first'] = $pdo->prepare("INSERT INTO table SET col1 = :val, col2 = :val2");
$insert['second'] = $pdo->prepare("INSERT INTO another_table SET col1 = :val, col2 = :val2");
$pdo->beginTransaction();
$insert['first']->bindValue(':val', 'your value');
$insert['first']->bindValue(':val2', 'anothervalue');
$insert['first']->execute();
$insert['second']->bindValue(':val', 'your value');
$insert['second']->bindValue(':val2', 'anothervalue');
$insert['second']->execute();
$pdo->commit();
The code above will save the data in two tables ONLY if both inserts are successful.
To paraphrase the accepted answer but with accent on mysqli.
The key is to configure mysqli to throw exceptions and to use a transaction.
A transaction will ensure that all operations either complete in their entirety or have no effect whatsoever. Another important advantage of using a transaction is that it makes multiple inserts faster, eliminating all possible delays that could be caused by separate query execution.
To use transactions with mysqli you need to do as follows:
First of all, make sure you have a proper mysqli connection, which, among other things, tells mysqli to throw an exception in case of error. Then just prepare your queries, start a transaction, execute the queries and commit the transaction - just like it is shown in the accepted answer, but with mysqli:
include 'mysqli.php';
$stmt1 = $mysqli->prepare("INSERT INTO table SET col1 = ?, col2 = ?");
$stmt2 = $mysqli->prepare("INSERT INTO another_table SET col1 = ?, col2 = ?");
$mysqli->begin_transaction();
$stmt1->bind_param("ss", $col1, $col2);
$stmt1->execute();
$stmt2->bind_param("ss", $col1, $col2);
$stmt2->execute();
$mysqli->commit();
Thanks to exceptions and transactions there is no need to verify the result of each query manually.

MySQL Statement is not working in PHP but works perfectly fine in MySQL Workbench [duplicate]

I want to run mysql queries to insert data from a custom html form.
Here I have to insert multiple set of data, some data to one table and some to other. Currently I am using the simple approach to send data to php page using jquery ajax and run multiple mysqli_query() functions one after another. But I guess when there will be large number of users, there will be problems related to speed. So can anyone suggest me a better way to do the same.
There are 5 tables in the database and each table has 7 to 10 columns that need to get different set of data, every time.
I want to run each query only if the previous insert query is successfully completed.
That's why I am checking for the result every time and then running the next query, which makes me feel the issue of speed on large user base.
The problem is, I need to insert data to first table and if its successfully inserted then only run query for the second table.
This means you need a transaction.
A transaction is a set of queries that either all execute ok or if one fails - they all fail. This is to ensure you don't end up with crap data in your tables.
Do not
Do not use multiquery.
Do not use mysql_* function(s).
Do not use bulk inserts.
People telling you to do that just have absolutely no clue what they're doing, ignore them.
Do
Use PDO
Use prepared statements
Prepare the statement(s) ONCE, use them MULTIPLE times
Sample code - do NOT copy paste
$dsn = 'mysql:dbname=testdb;host=127.0.0.1;charset=utf8mb4';
$user = 'dbuser';
$password = 'dbpass';
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$insert['first'] = $pdo->prepare("INSERT INTO table SET col1 = :val, col2 = :val2");
$insert['second'] = $pdo->prepare("INSERT INTO another_table SET col1 = :val, col2 = :val2");
$pdo->beginTransaction();
$insert['first']->bindValue(':val', 'your value');
$insert['first']->bindValue(':val2', 'anothervalue');
$insert['first']->execute();
$insert['second']->bindValue(':val', 'your value');
$insert['second']->bindValue(':val2', 'anothervalue');
$insert['second']->execute();
$pdo->commit();
The code above will save the data in two tables ONLY if both inserts are successful.
To paraphrase the accepted answer but with accent on mysqli.
The key is to configure mysqli to throw exceptions and to use a transaction.
A transaction will ensure that all operations either complete in their entirety or have no effect whatsoever. Another important advantage of using a transaction is that it makes multiple inserts faster, eliminating all possible delays that could be caused by separate query execution.
To use transactions with mysqli you need to do as follows:
First of all, make sure you have a proper mysqli connection, which, among other things, tells mysqli to throw an exception in case of error. Then just prepare your queries, start a transaction, execute the queries and commit the transaction - just like it is shown in the accepted answer, but with mysqli:
include 'mysqli.php';
$stmt1 = $mysqli->prepare("INSERT INTO table SET col1 = ?, col2 = ?");
$stmt2 = $mysqli->prepare("INSERT INTO another_table SET col1 = ?, col2 = ?");
$mysqli->begin_transaction();
$stmt1->bind_param("ss", $col1, $col2);
$stmt1->execute();
$stmt2->bind_param("ss", $col1, $col2);
$stmt2->execute();
$mysqli->commit();
Thanks to exceptions and transactions there is no need to verify the result of each query manually.

How to run multiple insert query in SQL using PHP in one go?

I want to run mysql queries to insert data from a custom html form.
Here I have to insert multiple set of data, some data to one table and some to other. Currently I am using the simple approach to send data to php page using jquery ajax and run multiple mysqli_query() functions one after another. But I guess when there will be large number of users, there will be problems related to speed. So can anyone suggest me a better way to do the same.
There are 5 tables in the database and each table has 7 to 10 columns that need to get different set of data, every time.
I want to run each query only if the previous insert query is successfully completed.
That's why I am checking for the result every time and then running the next query, which makes me feel the issue of speed on large user base.
The problem is, I need to insert data to first table and if its successfully inserted then only run query for the second table.
This means you need a transaction.
A transaction is a set of queries that either all execute ok or if one fails - they all fail. This is to ensure you don't end up with crap data in your tables.
Do not
Do not use multiquery.
Do not use mysql_* function(s).
Do not use bulk inserts.
People telling you to do that just have absolutely no clue what they're doing, ignore them.
Do
Use PDO
Use prepared statements
Prepare the statement(s) ONCE, use them MULTIPLE times
Sample code - do NOT copy paste
$dsn = 'mysql:dbname=testdb;host=127.0.0.1;charset=utf8mb4';
$user = 'dbuser';
$password = 'dbpass';
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$insert['first'] = $pdo->prepare("INSERT INTO table SET col1 = :val, col2 = :val2");
$insert['second'] = $pdo->prepare("INSERT INTO another_table SET col1 = :val, col2 = :val2");
$pdo->beginTransaction();
$insert['first']->bindValue(':val', 'your value');
$insert['first']->bindValue(':val2', 'anothervalue');
$insert['first']->execute();
$insert['second']->bindValue(':val', 'your value');
$insert['second']->bindValue(':val2', 'anothervalue');
$insert['second']->execute();
$pdo->commit();
The code above will save the data in two tables ONLY if both inserts are successful.
To paraphrase the accepted answer but with accent on mysqli.
The key is to configure mysqli to throw exceptions and to use a transaction.
A transaction will ensure that all operations either complete in their entirety or have no effect whatsoever. Another important advantage of using a transaction is that it makes multiple inserts faster, eliminating all possible delays that could be caused by separate query execution.
To use transactions with mysqli you need to do as follows:
First of all, make sure you have a proper mysqli connection, which, among other things, tells mysqli to throw an exception in case of error. Then just prepare your queries, start a transaction, execute the queries and commit the transaction - just like it is shown in the accepted answer, but with mysqli:
include 'mysqli.php';
$stmt1 = $mysqli->prepare("INSERT INTO table SET col1 = ?, col2 = ?");
$stmt2 = $mysqli->prepare("INSERT INTO another_table SET col1 = ?, col2 = ?");
$mysqli->begin_transaction();
$stmt1->bind_param("ss", $col1, $col2);
$stmt1->execute();
$stmt2->bind_param("ss", $col1, $col2);
$stmt2->execute();
$mysqli->commit();
Thanks to exceptions and transactions there is no need to verify the result of each query manually.

How to execute two sql queries in php?

I am trying to execute this code in a php page to store some data on my database.
The thing is that I want to Insert data, but due to a foreign key constraint it is impossible. So, in my php code I want to execute two sql queries. The first one to disable foreign key checks and the second one to insert the data.
When I try it in phpmyadmin it works. But manually. I would like to put it on php code.
This is my code. The parameter $conexion is the one that executes my sql queries.
Any ideas?
$sql = "SET foreign_key_checks=0";
$sql. = "INSERT INTO routes (title, distance, subtitle) VALUES ('".$_POST['title']."','".$_POST['distance']."', '".$_POST['subtitle']."');";
$conexion->multi_query($sql);
Try to avoid using multi_query. Sending a small query to the MySQL server doesn't really affect performance and does prevent kind of limit the effect of something like SQL injection.
In your case there's no need for multi_query. If you send two queries in a script, both go over on the same connection. The SET query affect the current connection.
// Protect against SQL injection
$title = $conexion->escape_string($_POST['title']);
$distance = $conexion->escape_string($_POST['distance']);
$subtitle = $conexion->escape_string($_POST['subtitle']);
// Execute queries
$conexion->query("SET forgeign_key_checks=0");
$conexion->query("INSERT INTO routes (title, distance, subtitle) VALUES ('$tittle', '$distance', '$subtitle')");
Apart from the comment above, you need a semi-colon between your sql statements
multi_query - Executes one or multiple queries which are concatenated by a semicolon.

Placeholder For SQLite table In PHP

I have a query I would like to use that I would like to be reused for other select queries.
Is it possible to have a select query like this:
SELECT * FROM ? WHERE id = ?;
And then bind the values like this:
$stmt->bindValue(1, $table, PDO::PARAM_STR);
$stmt->bindValue(2, $id, PDO::PARAM_INT);
The problem is when I do this I get this $database->errorInfo() from a PDOException
HY000 1 near "?" syntax error.
I have tried taking out the table placeholder and it does work. Is it possible to do it my way or do I need to have separate functions?
Short answer: NO.
Long answer:
Refer to the PDO::prepare manual. There is a statement: This must be a valid SQL statement for the target database server. This means that your DB backend have to support prepared statement syntax that you use.
As far as I know, neither mysql, nor any other DB does not allow binding variables to occur in FROM clause. The reason for that lays deep in the concept of prepared statement. Prepared statement is being prepared inside the DB when you are calling prepare. This means that DB planner builds a plan for the query, so it can be executed multiple times with different parameters without building it again and again. To build a plan, planner needs to know affected tables, functions called, opportunities to use different fetch and join strategies (index scans/nested loops/etc.) and so on.
So, you cant 'bind' table name into prepared statement at the moment you want it to run, because DB needs table names at the moment when you prepare the statement. That's why you receive that message: DB requires all table names to be present in the preparing query.

Categories