This question already has answers here:
PHP MySQLi Multiple Inserts
(3 answers)
Closed 9 years ago.
I'm trying to figure out how to properly achieve multiple row inserts along the format of
insert to tbl values (?,?,?), (?,?,?), (?,?,?);
The mysqli_bind_param doc is pretty clear on how to accomplish this for a single row.
From the docs their example looks like:
$stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$stmt->bind_param('sssd', $code, $language, $official, $percent);
However I have an multi-dimensional array where each inner element represents a value set, or row, to be inserted.
Well, you have 2 choices
Use the very prepared statement approach to do multiple inserts using once prepared query. Wrapped in a transaction they have to be blazingly fast
Create a dynamical call to bind_param which is going to be a pain, an unexpected pain. For some reason mysqli makes dynamical binding overcomplicated.
You will need to merge your array into single one, then create a second array for the references and then call call_user_func_array() for this latter approach. Dunno if it worth the mess.
Related
I have an array $authors with some numbers I want to insert into a table.
I can have a prepared statement to execute multiple times for each element from the array:
$stmt = $pdo->prepare('INSERT INTO authors (article_id, user_id) VALUES(?, ?)');
$stmt->bindParam(1, $article_id);
$stmt->bindParam($author);
foreach($authors as $author) {
$stmt->execute();
}
However, I can do a trick using implode() and execute the statement only once:
// here probably $authors = array_map('intval', $authors);
$stmt = $pdo->prepare(
'INSERT INTO authors (article_id, user_id)
VALUES ('.implode(', :article_id), (', $authors).', :article_id)');
$stmt->execute([':article_id' => $article_id]);
The first solution is more conventional and looks more securely.
The second (I think) is faster because there is only one query to the database. (and is shorter - there are no loops except in implode)
I don't see any security issues here but it looks safer (to me) when there are no string concatenations in queries.
Which is the proper way in this situation?
Edit: echo of the second query gives this:
INSERT INTO authors (article_id, student_id)
VALUES (121, :article_id), (50, :article_id)
And executes with no errors.
According to the PDO's doc "You cannot use a named parameter marker of the same name more than once in a prepared statement, unless emulation mode is on.". So that alone makes your "implode" solution bad.
That being said, I'll answer on the theory. The point of prepared statements is to compile the query only once, so repeated executions are faster. So prepared statements are meant to be used as in your first example : one simple "template" query, repeated many times.
In your second example, you make a custom query, that will hardly ever be repeated (since it's based on the content of your $authors array). Therefore, prepared statement in this case is completely useless, you have the overhead of the PREPARE without the benefits of repeated executions. It's not the way it's supposed to be used.
Extended insert is a perfectly valid solution, and a good one with that, but use it with normal query (i.e. exec()), and be sure to use quote() to protect against SQL-injection!
This question already has answers here:
Insert multiple rows with PDO prepared statements
(4 answers)
Closed 8 years ago.
Ok so i need to insert multiple rows into a database using MySql from one form, each row is a result. The was i started doing it is the following:
INSERT INTO results (1,2,3,4,5,6,7) VALUES (1,2,3,4,5,6,7), (8,9,10,11,12,13,14)
And so on, my question is:
I don't know how many rows of results a user will want to insert ( a maximum of 15 will apply). Is their a more practical way of achieving the same result? Or am I better off sticking to the way i originally planned?
1°) Use prepared statement (like in Java):
(For safe code, always use prepared statement and avoid generate SQL)
$stmt = $db->stmt_init();
$stmt->prepare("INSERT INTO foo_table (id, firstname, lastname) VALUES(?, ?, ?)");
foreach($myarray as $row)
{
$stmt->bind_param('iss', $row['id'], $row['firstname'], $row['lastname']);
$stmt->execute();
}
$stmt->close();
To understant "iss" param in bind_param: http://uk3.php.net/manual/fr/mysqli-stmt.bind-param.php
2°) Generate batch insert:
Batch inserts with PHP
This question already has answers here:
PHP MySQLi Multiple Inserts
(3 answers)
Closed 3 years ago.
Hoping someone can give me some insight here.
When having to insert multiple rows into a table at once, I've used sql that looks something like this:
INSERT INTO some_names (firstName, lastName) VALUES ('Joe', 'Smith'),('Fred','Sampson'),('Lisa','Pearce')
As you can see I'm inserting three rows with one statement. The reason I do this is that I believe it is more efficient than executing three distinct statements to insert the rows.
So my question is this: how do I do this if I want to be able to bind my values to a statement? Unfortunately I've been looking all over the web and I can only find example of single statements in the form of:
$stmt = $mysqli->prepare("INSERT INTO some_names (firstName, lastName) VALUES (?, ?)");
$stmt->bind_param('ss', $firstName, $lastName);
$firstName = "Joe";
$lastName = "Smith";
$stmt->execute();
$firstName = "Fred";
$lastName = "Sampson";
$stmt->execute();
It seems that this would be the equivalent of doing separate INSERT statements and seems to be less efficient.
So my question is: Is there any way to bind in a multi-insert statement? Please educate me here! Thanks
Simple:
$stmt = $mysqli->prepare("INSERT INTO some_names (firstName, lastName) VALUES (?, ?),(?,?),(?,?)")
$stmt->bind_param('ssssss', 'Joe', 'Smith','Fred','Sampson','Lisa','Pearce');
It seems that this would be the equivalent of doing separate INSERT statements and seems to be less efficient.
No, it’s not less efficient – because a statement is prepared only once (to figure out what it is supposed to do), and after that is done only the data is send to the database afterwards.
You are looking at this the wrong way.
You would pretty much never do what you have shown above, it would almost always be done in a loop. And even if you dynamically constructed (?, ?), (?, ?), (?, ?) you would still have to loop to build the query string and bind the data (which would get even more complicated because of MySQLi's ridiculous insistance on by-ref bindings) so it wouldn't gain you anything in terms of work that needs to be done by PHP - you just moved the loop - and it would lose you a lot in terms of readability.
It does have a gain in round trips to the database (assuming you are always inserting more than one row) - but this would only make a meaningful difference when inserting hundreds or thousands or rows, in which case you are most likely performing some kind of import operation, in which case the extra couple of seconds probably don't matter (it won't be e.g. slowing a page load).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Php PDO::bindParam data types.. how does it work?
Could someone explain - why is prepared statement more secure:
$stmt = $conn->prepare("INSERT INTO users (user, pass, salt)
VALUES (:user, :pass, :salt");
$stmt->bindParam(":user", $user);
$stmt->bindParam(":pass", $pass);
$stmt->bindParam(":salt", $salt);
$stmt->execute();
Insert query is firstly prepared with placeholders, then values is placed instead placeholders, but - where is that famous secure point ?
The values are not placed into the placeholders (depending on the backend, some do emulation but lets not talk about them, as that's not prepared statements). The issue with traditional SQL is that the commands and data are mixed. Prepared statements get around that issue by intentionally keeping them separate at all times. Prepared statements aren't just a fancy way to automatically do mysqli_real_escape_string.
Related question, but not helpful to me: Why cant you pass MYSQL functions into prepared PDO statements?
Here's the deal: I'm writing an abstraction layer to PHP PDO and implementing a query builder.
This exact problem is occurring only in INSERT statements. Here's an example of my code:
$db->insert('table_name')
->keys(array('abc', 'def', 'ghi'))
->values(array($var1, $var2, $var3)) // can take a 2D array if you want to insert multiple rows at the same time
->execute();
The underlying code builds the query string with ?'s instead of values. For this particular example the query would result in the following:
INSERT INTO `table_name`
(`abc`, `def`, `ghi`)
VALUES
(?, ?, ?)
Upon calling execute(), it passes the values to PDOStatement::execute() as single dimension array (i.e. all values associated with the question marks are put in a single array). And this is where the problems start - the PDOStatement::execute() does not process MySQL functions as such, but quotes them as strings, thus breaking the query:
INSERT INTO `table_name`
(`abc`, `def`, `ghi`)
VALUES
('123', 456, 'NOW()') -- error, incorrect datetime value: 'NOW()'
The question is - how do I make this work while still maintaining the same interface? I know I could just check if the value of the column is a MySQL function and put it in directly instead of the question mark, but there are many functions one could use there and that would suck.
Edit: so it seems that for now the easiest option would be to simply set the values to leave alone like this: $var3 => 'noquote'. It's not really a good one, but it works.
Add another argument for that method:
table name
values (as associative array)
sql (as associative array)
Keep in mind, that you cannot use '?' when you want to do access the columns, e. g. in COLUMN1 + 1 or COLUMN1 + COLUMN2.
I procede like that:
$bdd->prepare(INSERT INTO `table_name` (`abc`, `def`, `ghi`) VALUES (?, ?, ?))
$bdd->execute(array('abcValue', 'devValue', 'ghiValue'))
Your last query comes up with an error ( -- error, incorrect datetime value: 'NOW()')
Try formatting your date like this instead:
DATE_FORMAT(now(), '%Y-%m-%d %H:%i:%s'))