Strange behavior of mysqli_query - php

I ran into a problem with strange behavior of mysqli_query. There's a foreach-loop to update table rows but the update for the last loop doens't get written to the database (all the other updates get written successfully). There's no error and mysqli_affected_rows returns 1 as it should. The code pases through till the end, confirmed by an echo-statement after mysqli_query.
I tried to loop trough an array with only one element and the same problem.
What's going on here? Does anyone ran into the same problem?
OK...here's the significant part of the code, the whole code isn't possible cause there maximum 30000 characters allowed. I also echoed out the sql-string and everything is perfect. But as I said the update for the last loop (the last time when the loop is beeing executed) doesn't get written to the MySQL-DB.
$sql_getRelations = "SELECT id_machine, device_id, serial_number, variant_id, company_id, last_file FROM view_machines "
. "WHERE company_id NOT IN ('" . implode( '\',\'' , $btc_companies) . "') "
// . "AND id_machine = 158 "
. "AND device_type_id = 4 AND machine_status = 'active' "
. "ORDER BY id_machine ASC;";
$result_relations = mysqli_query($db_ed, $sql_getRelations);
$relations_arr = mysqli_fetch_all($result_relations, MYSQLI_ASSOC);
mysqli_free_result($result_relations);
foreach($relations_arr as $machine){
//...some other code here
$sql_update_device = "UPDATE device SET last_file = '" . $str_max_ts . "' WHERE id_device = " . $machine['device_id'] . ";";
$update_device = mysqli_query($db_ed, $sql_update_device);
if (!$update_device) {
error_log("\r\n" . date("Y-m-d H:i:s") . ': !!!!Updatefehler device: ' . $machine['device_id'] . ": " . mysqli_error($db_ed), 3, "C:/xampp/htdocs/cronjob/error_log.txt");
}
echo $machine['id_machine'] . ', ';
}
mysqli_close($db_ed);

I would perform debugging like the following to a text file. Wedge your data collection in the outer loops then rem that out and zero in on inner chunks. A divide and conquer strategy.
I would have tried to get my head into your email php but it is 675 lines of one foreach block :p
PHP:
<?php
//mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
mysqli_report(MYSQLI_REPORT_ALL);
error_reporting(E_ALL); // report all PHP errors.
ini_set("display_errors", 1);
echo "start<br/>";
// $file="/home/nate/debug123.txt";
$file="c:\\nate\\debug123.txt";
date_default_timezone_set('America/New_York');
$debugStr=date('Y-m-d H:i:s').": Start";
file_put_contents($file, $debugStr."\n", FILE_APPEND | LOCK_EX);
try {
$mysqli= new mysqli('localhost', 'theUser', 'thePassword', 'theDB_Name');
if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') '
. $mysqli->connect_error);
}
echo "I am connected and feel happy.<br/><br/>";
$query = "INSERT INTO `t921`(`thing`,`uniqueNum`,`views`) values ('aaa',577,0)"; // change that 577 each time else it fails unique
echo $query."<br>";
$mysqli->query($query);
$debugStr=date('Y-m-d H:i:s').": Affected rows: " .$mysqli->affected_rows.", Insert id: ".$mysqli->insert_id;
echo $debugStr."<br><br>";
file_put_contents($file, $debugStr."\n", FILE_APPEND | LOCK_EX);
$query = "UPDATE `t921` SET `views`=`views`+1 WHERE id=1";
echo $query."<br>";
$mysqli->query($query);
$id=1;
$debugStr=date('Y-m-d H:i:s').": UPDATE id=".$id.", Affected rows: " . $mysqli->affected_rows;
echo $debugStr."<br><br>";
file_put_contents($file, $debugStr."\n", FILE_APPEND | LOCK_EX);
$query = "UPDATE `t921` SET `views`=`views` WHERE id=1";
echo $query."<br>";
$mysqli->query($query);
$id=1;
$debugStr=date('Y-m-d H:i:s').": UPDATE id=".$id.", Affected rows: " . $mysqli->affected_rows;
echo $debugStr."<br><br>";
file_put_contents($file, $debugStr."\n", FILE_APPEND | LOCK_EX);
$mysqli->close();
} catch (mysqli_sql_exception $e) {
throw $e;
}
?>
Sample log file (debug123.txt):
2016-09-19 18:23:57: Start
2016-09-19 18:23:57: Affected rows: 1, Insert id: 27
2016-09-19 18:23:57: UPDATE id=1, Affected rows: 1
2016-09-19 18:23:57: UPDATE id=1, Affected rows: 0
Note the last update stmt was meant to change no data thus affected=0
Schema:
create table t921
( id int auto_increment primary key,
thing varchar(100) not null,
uniqueNum int not null,
views int not null,
unique key(uniqueNum)
);

Related

how to optimize this sql insertion php code?

I have mysql database and I want to insert about 40'000 rows into it from PHP code , but my code takes more than 15 minutes to insert the rows, is there any chances to optimize it? where is my problem(PHP code / database design) ?
here are the details:
- the row data are stored in a utf-8 txt file the values separated by "\t" tab character and every row sets in one line of the file, like this
string view:
"value1\tvalue2\tvalue3\value4\value5\r\nvalue1\tvalue2\tvalue3\value4\value5\r\nvalue1\tvalue2\tvalue3\value4\value5\r\nvalue1\tvalue2\tvalue3\value4\value5\r\n"
text reader view:
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
value1 value2 value3 value4 value5
-the data base has 3 tables as this:
table1 countries fields(1) (NAME varchar -primarykey-)
table2 products fields(2) (HS varchar - primarykey-, NAME varchar)
table3 imports fields (6) (product_hs varchar -foreignkey->products(HS),
counteryname varchar - foreignkey->countries (NAME),
year year,
units int,
weight int,
value int)
- php code was like this
$conn = new mysqli($hn,$un,$pw,$db);
if($conn->connect_error) {die($conn->connect_error);}
$x = 0; // row counter
ini_set('max_execution_time', 3000);
while(!feof($filehandle)){
$x++;
echo $x . ": ";
$fileline = fgets($filehandle);
$fields = explode("\t", $fileline);
$query = "INSERT INTO imports(product_hs,counteryname,year,units,weight,value) VALUES(" . "'" . $fields[0] ."','". $fields[1] . "','2014','". $fields[2] . "','" . $fields[3] . "','" . $fields[4] . "');";
$result = $conn->query($query);
if(!$result) {
echo $conn->error . "</br>";
}else{
echo $result . "</br>";
}
};
first I thought it is an index problem that slows down the insertion , so I removed all the indexes from "imports" table , but it didn't go faster!!
is the problem from the database design or from my php code?
also note that the browser is notifying "waiting for response from the server" for the first 5 minutes then most of the remaining time is notifying "transferring data from server", is this because the response html has more than 40'000 line for the row counter1:1 </br> 2:1 </br> .....(declared in the php code)?
please consider I'm very newbie, thanks.
Thank you very much tadman and Hanlet EscaƱo and Uueerdo and Julie Pelletier and Solarflare
for helping me in the comments.
I did 3 different changes in my PHP code using the approaches you suggested in the comments, then I tested the results and here are the tests results.
The conclusion of the 3 tests: as tadman suggested, the key is in LOAD DATA INFILE . it dramatically reduced the execution time to less than 7 seconds, and these are the 3 tests.
ORIGINAL CODE: ~ 26 minutes
TEST 1 : ~ 34 minutes
(as Uueerdo suggested I removed the echo statements and the rows counter from the loop)
while(!feof($filehandle)){
// $x++; // commented out
//echo $x . ": "; // commented out
$fileline = fgets($filehandle);
$fields = explode("\t", $fileline);
$query = "INSERT INTO products(hs,arabicname,englishname) VALUES(" . "'" . str_replace("'", ".", $fields[0]) ."'," . "'". str_replace("'", ".", $fields[1]) . "'," . "'". str_replace("'", ".", $fields[2]) . "');";
$result = $conn->query($query);
/* // commented out
if(!$result) {echo $conn->error . "</br>";}
}else{echo $result . "</br>";}
*/};
TEST 2 : ~ 7 seconds
(As tadman said I searched for LOAD DATA INFILE and it was super powerful
//replace the entire loop with this simple query
$query = "LOAD DATA LOCAL INFILE'" .
addslashes("C:\\xampp\\htdocs\\bots\\impandexp\\imports.txt")
. "' INTO TABLE imports FIELDS TERMINATED BY '\t' LINES TERMINATED BY
'\r\n'(product_hs,counteryname,units,weight,value) SET year = '2014';";
$result = $conn->query($query);
TEST 3 : ~ 5 seconds
It was the same as test 2 except that I found useful tips on the same page that tadman give, that help in maximizing the speed for.
Bulk Data Loading for InnoDB Tables
// turning off index checks that might slows down bulk data insertion
$query = "SET foreign_key_checks=0;";
$conn->query($query);
$query = "SET unique_checks=0;";
$conn->query($query);
$query ="SET autocommit=0;";
$conn->query($query);
$query = "LOAD DATA LOCAL INFILE'" . addslashes("C:\\xampp\\htdocs\\bots\\impandexp\\imports.txt") . "' INTO TABLE imports FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\r\n'(product_hs,counteryname,units,weight,value) SET year = '2014';";
$result = $conn->query($query);
echo $result . "</br>";
// turning them on again
$query = "SET foreign_key_checks=1;";
$conn->query($query);
$query = "SET unique_checks=1;";
$conn->query($query);
$query ="COMMIT;";
$conn->query($query);

Mysql update table column from one database to another

I am working on a script that updates from:
tendesig_zink_production | euid0_hikashop_product | product_quantity
to:
tendesig_zink_dev | euid0_hikashop_product | product_quantity
I have to do this because our inventory numbers are stored on the production instance. so before pushing a new version from our dev instance i have to update the dev's inventories from production prior to the push. I am a lot rusty with my mySQL, this is what i have so far I need to know what the proper query would be though.
<?php
$host1="localhost"; // destination
$base1="tendesig_zink_dev";
$user1="tendesig_zink";
$password1="1,&#GZAWiB5z";
$host2="localhost"; //source
$base2="tendesig_zink_production";
$user2="tendesig_zink";
$password2="1,&#GZAWiB5z";
$conection1 = #mysql_connect($host1, $user1, $password1)
or die("Error reaching destination<br>".mysql_error()." nr eroare: ".mysql_errno());
print "Succesfuly connected 1! <br>";
$Db1 = #mysql_select_db($base1, $conection1)
or die("Error reaching destination database:<br>" . mysql_error(). "<br>" . mysql_errno());
print "Database1 reached!<br>";
$conection2 = #mysql_connect($host2, $user2, $password2)
or die("Error reaching source<br>".mysql_error()." nr eroare: ".mysql_errno());
print "Succesfuly connected 2!<br>";
$Db2 = #mysql_select_db($base2, $conection2)
or die("Error reaching source database:<br>" . mysql_error(). "<br>" . mysql_errno());
print "Database2 reached!!<br>";
$query = 'create table destination_table select * from second_database.source_table';
//echo "<br>".$query."<br>";
$result2 = mysql_query($query2, $conection1) or die('Query failed: ' . mysql_error().'||'.mysql_errno());
mysql_close($conection1);
mysql_close($conection2);
?>
Your query is wrong. You want to do something like this:
CREATE TABLE destination_database.destination_table LIKE source_database.source_table
Then run this:
INSERT INTO destination_database.destination_table
SELECT * FROM source_database.source_table
In (untested) PHP code:
$create_query = 'CREATE TABLE destination_database.destination_table LIKE source_database.source_table';
$result = mysql_query($create_query, $conection1) or die('Query failed: ' . mysql_error().'||'.mysql_errno());
$insert_query = 'INSERT INTO destination_database.destination_table SELECT * FROM source_database.source_table';
$result = mysql_query($insert_query , $conection1) or die('Query failed: ' . mysql_error().'||'.mysql_errno());

Can't get score to update with this mysql statement

I'm guessing that I'm just a little rusty or something because it seems like this should be working. Am I missing something here...
Here is the code I am trying to use...
<?php
echo dbConn();
$existing_time = mysql_result(mysql_query("SELECT p_time FROM scores WHERE p_uid=$uid"), 0);
$existing_category = mysql_result(mysql_query("SELECT p_cat FROM scores WHERE p_uid=$uid AND p_cat=$pieces"), 0);
if ($existing_category == "") {
mysql_query(
"INSERT INTO scores VALUES (
'',
'$uid',
'$pusername',
'$time',
'$pieces'
)");
} elseif ($existing_time <= $time) {
echo "No Change! Old Score Was Better (Lower)";
} elseif ($existing_time > $time) {
mysql_query("UPDATE scores SET p_time = " . $time . " WHERE p_uid = " . $uid . " AND p_cat = " . $pieces . "");
};
?>
Now... Here is what I am trying to do...
I am collecting info from the database where the users username AND category match. If the category for that user does not exist, it inserts the latest score. (This much works.)
Then, if the category does exist but the old score is better, it just does nothing. (This part works too)...
However, what I can't seem to do is get it to update the last score, if the current score is better (lower score, since this is a time based game.) It doesn't update the score.
I am trying it this way: By updating a row in "scores" where the USERNAME and the CATEGORY match at the same time.
Please note... where it says "pieces". this is a category. Where it says "time", this is a score. The score is returned as 00:00:00 for hours minutes and seconds.
EXAMPLE: (in parentheses is the database row name)
id (ID) = just KEY id in sequencial order
user id (p_uid) = 123456789
username (p_username) = somename
score (p_time) = 00:01:03
category (p_cat) = 10
Change you update statement to:
mysql_query("UPDATE scores SET p_time = '" . $time . "' WHERE p_uid = " . $uid . " AND p_cat = " . $pieces . "");
You have missed quotes in the update statement around $time.

delete a mysql record using multiple selectors

I am trying to delete a record in a MYSQL database when I need to select two simultaneous columns with the WHERE clause:
$result3 = mysqli_query($con, " DELETE FROM Waiting WHERE ToUser='$ToEmail' AND ImageID='$ToEmailDB' ");
if ($result3==false) {
echo "No images waiting for " . $ToEmail . " for image " . $ToEmailDB;
}
else {
echo "Image and record deleted for " . $ToEmail . " for image " . $ToFileName . ".jpg and record " . $GuessImageID;
}
When I execute this statement $result3 returns true but the entry is not deleted. What do I need to change in my formatting? The strings echo back correct data entered in the table.
Shouldn't it be,
"DELETE from Waiting WHERE ToUser = '" . $ToEmail . "' AND ImageID = '" . $ToEmailDB . "'"
$result3 = mysqli_query($con, "DELETE FROM Waiting WHERE ToUser='".$ToEmail."' AND ImageID='".$ToEmailDB."' ");
The query will return true if the SQL query executes successfully, even when the DELETE didn't remove any rows in the DB.
http://php.net/manual/en/mysqli.affected-rows.php
To answer your question, you need to find the number of rows affected
$result3 = mysqli_query($con, " DELETE FROM Waiting WHERE ToUser='$ToEmail' AND ImageID='$ToEmailDB' ");
if (!$result3) {
echo "A database error occurred";
}
else if (mysqli_affected_rows($con) == 0) {
echo "No images waiting for " . $ToEmail . " for image " . $ToEmailDB;
}
else {
echo "Image and record deleted for " . $ToEmail . " for image " . $ToFileName . ".jpg and record " . $GuessImageID;
}
Your query always returns TRUE if its executed successfuly. Only on query failures it returns FALSE As per the PHP documentation:
mysqli_query() Returns FALSE on failure. For successful SELECT, SHOW,
DESCRIBE or EXPLAIN queries mysqli_query() will return a mysqli_result object.
For other successful queries mysqli_query() will return TRUE.
From Moby04's Comment
If you want to check if something was actually deleted use mysqli_affected_rows() function.

MYSQL/PHP outputting entire table when I only want to output one row

This is definitely a beginner's question. There are two issues. The id in my MYSQL table (set to autoincrement) keeps going up, even though I delete rows from my table (I'm using phpmyadmin). As for the other issue, I can't seem to find a way to work with the row most recently entered by the user. The code echos all existing rows from MYSQL.
I've bolded the most pertinent section of code.
<?php
//establish connection to mysql
$con = mysql_connect("localhost","root","");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
/*retrieve user input from input form
and initialize variables */
$Word1 = $_POST["Word1"];
$Word2 = $_POST["Word2"];
$Word3 = $_POST["Word3"];
$Word4 = $_POST["Word4"];
$Word5 = $_POST["Word5"];
//select db
mysql_select_db("madlibs", $con);
//insert user input for word 1
$sql = "INSERT INTO test (Word1, Word2, Word3, Word4, Word5)
VALUES
('$Word1', '$Word2', '$Word3', '$Word4', '$Word5')";
if(!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}
$result = mysql_query ("SELECT * FROM test");
/* take note here */
while($row = mysql_fetch_array($result))
{
echo $row['Word1'] . " " . $row['Word2'] . " " . $row['Word3'] . " " .
$row['Word4'] . " " . $row['Word5'] . " " . $row['id'];
echo "<br />";
} /* take note here */
mysql_close($con);
?>
$result = mysql_query ("SELECT * FROM test order by id desc limit 1");
As for your id question...that's how ids work. They don't fill in gaps.
On a side note: Never ever put user submitted data directly into the query string. Always escape them with mysql_real_escape_string().
SELECT * FROM test ORDER BY Id DESC LIMIT 1

Categories