Bulk insert using PDO and PHP variable containing all database values - php

I am new to PHP and am trying to update a deprecated code from mysql to PDO.
Considering that the variable $insert contains all values to bulk insert such as:
('82817cf5-52be-4ee4-953c-d3f4ed1459b0','1','EM3X001P.1a','04.03.10.42.00.02'),
('82817cf5-52be-4ee4-953c-d3f4ed1459b0','2','EM3X001P.2a','04.03.10.33.00.02'),
...etc 13k lines to insert
here is the deprecated code:
mysql_connect('localhost', 'root', '') or die(mysql_error());
mysql_select_db("IPXTools") or die(mysql_error());
if ($insert != '')
{
$insert = "INSERT INTO IPXTools.MSSWireList (ID,Record,VlookupNode,HostWireLocation) VALUES ".$insert;
$insert .= "ON DUPLICATE KEY UPDATE Record=VALUES(Record),VlookupNode=VALUES(VlookupNode),HostWireLocation=VALUES(HostWireLocation)";
mysql_query($insert) or die(mysql_error());
$insert = '';
}
here is the new code:
try
{
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //set the PDO error mode to exception
// prepare sql and bind parameters
$stmt = $conn->prepare("INSERT INTO IPXTools.MSSWireList (ID, Record, VlookupNode, HostWireLocation)
VALUES (:ID, :Record, :VlookupNode, :HostWireLocation)");
$stmt->bindParam(':ID', $ID);
$stmt->bindParam(':Record', $Record);
$stmt->bindParam(':VlookupNode', $VlookupNode);
$stmt->bindParam(':HostWireLocation', $HostWireLocation);
// insert a row
// loop through all values inside the $insert variable??????? how?
$stmt->execute();
}
catch(PDOException $e)
{
echo "Error: " . $e->getMessage();
}
$conn = null;
During my research I found an excellent post:
PDO Prepared Inserts multiple rows in single query
One method says I would have to change my $insert variable to include all the field names.
And other method says I dont have to do that. I am looking at Chris M. suggestion:
The Accepted Answer by Herbert Balagtas works well when the $data array is small. With larger $data arrays the array_merge function becomes prohibitively slow. My test file to create the $data array has 28 cols and is about 80,000 lines. The final script took 41s to complete
but I didnt understand what he is doing and I am trying to adapt my code to his. The PHP sintax is new to me so I am strugling with handling the arrays, etc...
I guess the starting point would be the variable $insert which contains all the database values I need.
Do I need to modify my $insert variable to include the field names?
Or I could just use its content and extract the values (how?) and include the values in a loop statement? (that would probably execute my 13k rows one at at time)
Thank you

If you have 13k records to insert, it is good for performance to do not use prepared SQL statement. Just generate SQL query in format like this:
INSERT INTO IPXTools.MSSWireList
(ID, Record, VlookupNode, HostWireLocation)
VALUES
('id1', 'r1', 'node1', 'location1'),
('id2', 'r2', 'node2', 'location2'),
...
('id13000', 'r13000', 'node13000', 'location13000');
What you may do for it - use maner of your legacy code. Your try block will looks loke this:
try
{
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->exec($insert);
}

Related

PHP how to get last insert IDs when call to database is in a wrapper

<?php
$sql = "insert into user (firstname, lastname) values (:firstname, :lastname)";
$arg = array("John", "Doe");
$stmt = pdo($sql, $arg);
$id = $pdo->lastInsertId();
print $id;
function pdo($sql, $args = NULL){
$dsn = "mysql:host=localhost;dbname=db;charset=utf8mb4";
try {
$pdo = new \PDO($dsn, "user", "123");
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
if (!$args){
return $pdo->query($sql);
}
$stmt = $pdo->prepare($sql);
$stmt->execute($args);
return $stmt;
}
?>
I use a wrapper to call database queries, this has always worked well.
Except for today when I need to get the last insert ID. The error is "Undefined variable pdo"
I see why there is an error message, but not sure what is the solution while at the same time keeping the wrapper function?
You might just want to have a function create the DB connection and let the application code use the PDO API directly. That would be simpler than trying to wrap all the functionality of the PDO API. It would get complicated to do that.
If you really need a wrapper around your PDO connection, then you may want to create a class with different methods operating on the same connection. The class could have a special insert method that returns the inserted ID as well as a fetch method to retrieve results.

How can I avoid inserting empty rows into MySQL when working with PHP variables that have no value?

I have searched for the last few hours on this and have come up empty.
I am using a sample piece of code that I have edited slightly to work as needed. It posts values to a MySQL table, each set to a respective row. What I would like to be able to do is have the code not create a row if the PHP variable does not have a value. I am still relatively new with MySQL but have been really digging in so please if you have an answer, help me understand some of the meaning behind it. Thank you for your help!
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "database";
$col1Val1 = $_POST['col1Val1'];
$col1Val2 = $_POST['col1Val2'];
$col1Val3 = $_POST['col1Val3'];
$col2Val1 = $_POST['col2Val1'];
$col2Val2 = $_POST['col2Val2'];
$col2Val3 = $_POST['col2Val3'];
$col3Val1 = $_POST['col3Val1'];
$col3Val2 = $_POST['col3Val2'];
$col3Val3 = $_POST['col3Val3'];
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// begin the transaction
$conn->beginTransaction();
// our SQL statements
$conn->exec("INSERT INTO tableName(column1, column2, column3)
VALUES ('$col1Val1', '$col2Val1', '$col3Val1'),
('$col1Val2', '$col2Val2', '$col3Val2'),
('$col1Val3', '$col2Val3', '$col3Val3')");
// commit the transaction
$conn->commit();
echo "New records created successfully";
}
catch(PDOException $e)
{
// roll back the transaction if something failed
$conn->rollback();
echo "Error: " . $e->getMessage();
}
$conn = null;
?>
The way that query is currently written with multiple value sets, it's going to insert three rows whether they're empty or not. You need to evaluate each row separately in order to avoid inserting empty ones.
You have two main options.
Prepare an INSERT statement with placeholders for one row of values, iterate your $_POST and only execute the statement with rows that aren't empty. This is what I would suggest. With only a maximum of three rows to insert, the performance hit of executing multiple queries should be minimal.
Build your INSERT statement dynamically, and append a set of values for each of the rows that aren't empty. This is fine too, and it is still possible to construct a prepared statement that way, but for something like this it seems more complicated than necessary.
My suggestion for option 1:
$sql = "INSERT INTO tableName(column1, column2, column3) VALUES (?, ?, ?)";
$statement = $conn->prepare($sql);
for ($i=1; $i <= 3; $i++) {
$row = [];
for ($j=0; $j <= 3; $j++) {
$row[] = $_POST["col{$i}Val{$j}"];
}
if (array_filter($row)) { // check if the row has any non-empty values
$statement->execute($row);
}
}
This could be simplified a bit if you changed the names of your form fields up a bit so that you could get the values from sub-arrays in $_POST.
So thank you to all who gave me some tips. I believe I came up with a solution that will work decently for anyone who comes across the same issue.
What I did was for each set of data that goes to its own row, I created an ID field "row#Data" in the HTML that is defaulted to 0 but changes to 1 if each value is filled out. Then I used the if statement for each row instead of checking each variable.
There may be other ways to do this dynamically but to ensure functionality, this is what I came up with.
if ($row1Data == 1) $conn->exec(INSERT INTO...
if ($row2Data == 1) $conn->exec(INSERT INTO...
if ($row3Data == 1) $conn->exec(INSERT INTO...
...

Insert Query In PHP OOP While Row Does Not Exist In DB

I'm working on a custom CMS using PHP OOP. Basically I have made a class that can add a new row to db.
My Class:
<?php
class Navigation
{
private $db;
public function __construct()
{
$this->db = new Connection();
$this->db = $this->db->dbConnect();
}
public function NewMenu($menu_name,$menu_numbers)
{
if (!empty($menu_name) && !empty($menu_numbers)) {
$sql = "INSERT INTO menu_nav "
. "(menu_name, menu_items) VALUES (?, ?)";
$ins = $this->db->prepare($sql);
$ins->bindParam(1,$menu_name);
$ins->bindParam(2,$menu_numbers);
$ins->execute();
} else {
header("Location: maint/php/includes/errors/009.php");
exit();
}
}
}
This class works fine but the problem is that I don't know how to check if the menu_name exists already in the table or not. And if yes ,it should receive the error message that "Data can not be inserted to db" for example. So if you know how to do this feature in PHP OOP ,please let me know cause I really need it.
There are two ways for this to work. For the first method you'll need to have a primary/unique key, which would cause the query to fail. Set PDO up with throwing exceptions on failures, and you can check the exceptions message for "duplicate key".
To do this you'd need to change the connection options, like this[1]:
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
Then pdo::exec() will throw an exception instead of just returning false.
For the second method you need to query the DB first, and then insert it if 0 rows are returned. The problem with this approach is that it can trigger race conditions. In which a duplicate row is inserted between the check and the INSERT query, by another, simultaneously running, script.
That's why I recommend doing it in the first manner. As you'd need to do it anyway, to catch the race conditions.
PS: As an alternative way of doing method 1, you could use ON DUPLICATE KEY in the SQL query. If you wanted to insert or update the data.
[1]: Copied from here https://phpdelusions.net/pdo
so you should check if row exists in table, and insert the data only if row doesn't exist(if i correctly understand your question). at first select the row with given menu name $ins = $this->db->prepare("SELECT FROM menu_nav (menu_name, menu_items) VALUES (?, ?)"); and then check if you got any data. go here , you will get the clue)

PHP/MySQL PDO/Update Rows

I'm here trying to update my DB rows without deleting/creating new ones all the time. Currently, my DB creates new entries everytime I run this block of code. Instead of spamming my DB, I just want to change some of the values.
<?php
try {
$conn = new PDO("mysql:host=localhost;port=3306;dbname=dbname", Username, password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e){
echo "Connection failed: " . $e->getMessage();
}
if(isset($_POST['mUsername']))
{
$mUsername = urldecode($_POST['mUsername']);
$mEvent = urldecode($_POST['mEvent']);
$mChat = urldecode($_POST['mChat']);
$mlongitude = urldecode($_POST['mlongitude']);
$mlatitude = urldecode($_POST['mlatitude']);
$sqlUPDATE = "UPDATE users
SET lastEvent=:lastEvent, lastChat=:lastChat,
lastLong=:lastLong, lastLatt=:lastLatt
WHERE name=:name";
$stmt = $conn->prepare($sqlUPDATE);
$stmt->bindParam(':lastEvent', $mEvent);
$stmt->bindParam(':lastChat', $mChat);
$stmt->bindParam(':lastLong', $mlongitude);
$stmt->bindParam(':lastLatt', $mlatitude);
$stmt->bindParam(':name', $mUsername);
$stmt->execute();
}
echo "successfully updated";
?>
My assumption is my final line, the $results area. I believe it's just treating this an a new entry instead of an update. How do I go about just replacing values? some values will not change, like the username, and sometimes longitude/latitude won't need to be changed. Would that have to be a separate query, should I split this in to two scripts? Or could I just enter a blank, null value? Or would that end up overwriting the ACTUAL last coordinates, leaving me with null values? Looking for any help or guides or tutorials. Thank you all in advance.
lots of syntax error in your code. It is simple to use bindParam
$sqlUPDATE = "UPDATE users
SET lastEvent=:lastEvent, lastChat=:lastChat,
lastLong=:lastLong, lastLatt=:lastLatt
WHERE name=:name";// you forget to close statement in your code
$stmt = $conn->prepare($sqlUPDATE);
$stmt->bindParam(':lastEvent', $mEvent);
$stmt->bindParam(':lastChat', $mChat);
$stmt->bindParam(':lastLong', $mlongitude);
$stmt->bindParam(':lastLatt', $mlatitude);
$stmt->bindParam(':name', $mUsername);
$stmt->execute();
read http://php.net/manual/en/pdostatement.bindparam.php
When using prepared statements, you should also make a habbit of following the set rules. Use named parameters. Try this:
if(isset($_POST['mUsername']))
{
$mUsername = urldecode($_POST['mUsername']);
$mEvent = urldecode($_POST['mEvent']);
$mChat = urldecode($_POST['mChat']);
$mlongitude = urldecode($_POST['mlongitude']);
$mlatitude = urldecode($_POST['mlatitude']);
$sqlUPDATE = "UPDATE users SET lastEvent= :lastEvent, lastChat= :lastChat, lastLong= :lastLong, lastLatt= :lastLatt WHERE name= :name";
$q = $conn->prepare($sqlUPDATE);
$results = $q->execute(array(':name'=>$mUsername, ':lastEvent'=>$mEvent, ':lastChat'=>$mChat, ':lastLong'=>$mlongitude, ':lastLatt'=>$mlatitude));
}

Inserting data to MySQL via PDO, trying to include a timestamp along with data using an array - getting errors?

I have a set of data stored in variables, and I want a page to write that data to a MySQL database, I'd like to include the time of insertion, here's my method:
$username="username"; $password="password";
try {
$pdo = new PDO('mysql:host=localhost; dbname=db01', $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('INSERT INTO table01
(
Time,
variable1,
variable2,
)
VALUES
(
:Time,
:variable1,
:variable2,
)');
$stmt->execute(array(
':Time' => NOW(),
':variable1' => $var1,
':variable2' => $var2,
));
echo $stmt->rowCount(); // 1
} catch(PDOException $e) {
echo 'Error: ' . $e->getMessage();
}
On loading this page, the css is stripped from the page, I get a sort of garbled output of what the page should look like (white screen, plain text some images), additionally on checking the database nothing has been written to it.
Without the Time variable in there, all works perfectly.
Any advice? Thanks in advance
Sorry, took me moment to re-read that. You are using the nysql function now() to do the work, and as such you don't need to set it as a param and therefore don't need to bind it at all. Just write it into your query.
$stmt = $pdo->prepare('INSERT INTO table01
(
Time,
variable1,
variable2,
)
VALUES
(
now(),
:variable1,
:variable2,
)');
$stmt->execute(array(
':variable1' => $var1,
':variable2' => $var2,
));
Edit Re Comment
The : in a query denotes it as a parameter in a prepared query. That means you must then bind it via the bind() command. However if you are inserting the data from within the database (such as using a built in function, or pulling the data in from another row) you don't need to declare it in the initial query with : and therefore you can't pass it to the query in the bound params array.

Categories