MySQL/PHP - inserting an extra row on INSERT statement - php

I am working on a small PHP + MySQL application. I have run into an issue where one of my insert statements seems to cause MySQL to add an additional somewhat blank row after each insert. Here's my setup:
I have a function that does the insert:
function addFacCertification($facultyID,$month,$year,$completed,$certificatesent,$confirmationtodean,$comments)
{
//echo "$facultyID<br>$month<br>$year<br>$completed<br>$certificatesent<br>$confirmationtodean<br>$comments";
$today = getdate();
$month = $today["mon"];
$date = $today["mday"];
$year = $today["year"];
$curdate = "$year" ."-". "$month" . "-" . "$date";
$sql = mysql_query("INSERT INTO facultycertification (facultyID,cmonth, cyear, completed, certificatesent, confirmationtodean, comments, certifiedon)
VALUES ('$facultyID', '$month', '$year', '$completed', '$certificatesent', '$confirmationtodean','$comments', '$curdate')");
return $sql;
}
Function call:
$sqlresults = addFacCertification($_POST["facultyID"], $_POST["month"], $_POST["year"], $_POST["completed"], $_POST["csent"],
$_POST["ctodean"], $_POST["comments"]);
Problem is, every time this is run - I get an extra row in my table: (See second row below) Image is here:
Any ideas why? Here is the table structure:
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
facultyID INT NOT NULL,
cmonth INT NOT NULL,
cyear INT NOT NULL,
completed INT NOT NULL,
certificatesent INT NOT NULL,
confirmationtodean INT NOT NULL,
comments TEXT,
certifiedon DATE,
FOREIGN KEY (facultyID) REFERENCES faculty(id)

I would imagine that your code is somehow being executed twice. I'd suggest the following (in this order) to debug the issue:
Uncomment that echo inside the function and see if it echos out twice (i.e. you're calling the function twice)
If you're running this via a web request tail the web server log to see if the request is being made twice
Enable general logging or enable profiling on the MySQL server to see what SQL queries are actually run against the server
You could have something like a MySQL trigger on the db doing this if you didn't set it up yourself but I think this is unlikely.

Related

MySQL procedures - incrementally recalculate rows

I have a quite trivial task of calculating budget entries (income/outcome/balance). There can be thousands of entries and I can change any of them in the middle. As the result, all later entries balance must be recalculated.
Right now I am doing it in PHP by iterating through array of all entries, and updating rows that changed. It takes too much time that way - my server stops responding for several minutes.
I suppose that it happens because PHP calls MySQL for every entry update, though for PHP itself this task of array iteration and recalculation is pretty cheap. I think that there must be a way to throw this task at MySQL, so it does the iteration/recalculation/update itself, which might be cheap as well.
I am not an expert in MySQL at all, but I heard that there are stored procedures that might be the cure.
Here is my MySQL (5.5.33) table:
CREATE TABLE `entry` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date DEFAULT NULL,
`is_income` tinyint(1) NOT NULL DEFAULT '0',
`income` decimal(20,2) DEFAULT NULL,
`outcome` decimal(20,2) DEFAULT NULL,
`balance` decimal(20,2) DEFAULT NULL,
PRIMARY KEY (`id`)
)
Here is my PHP (5.3.27):
//...
//$DB is a class for operating DB
$entries = $DB->get_all('entry'); //retrieves all entries from 'entry' table, sorted by date
$balance = 0;
foreach ($entries as $e) {
if ($e['is_income']) {
$balance += $e['income'];
} else {
$balance -= $e['outcome'];
}
if ($balance <> $e['balance']) {
$e1 = $e;
$e1['balance'] = $balance;
$DB->update('entry', $e1); //update the row by doing query('UPDATE `entry` ... WHERE id=' . $entry_id);
}
}
Can you point me the right direction? Thanks!
I think you can do this in a single SQL UPDATE query, no procedure needed.
UPDATE entry AS e1
JOIN (SELECT * FROM entry ORDER BY date) AS e2 ON e1.id = e2.id
CROSS JOIN (SELECT #balance := 0) AS var
SET e1.balance = (#balance := #balance + IF(e2.is_income, e2.income, -e2.outcome))
The user variable #balance serves the same purpose as the PHP variable $balance. The subquery is needed because MySQL doesn't allow use of ORDER BY in a multi-table UPDATE query, so you need to join with a subquery that produces the IDs in date order.
The "proper" way is to do the summation when displaying the report, and not store it in the table.
For only "thousands", it should not be a performance problem.

PHP mysqli - updating value of enum field results in empty string, but same query works when run in PHPMyAdmin

The query:
UPDATE caption_queue SET status = 'Conversion Completed' WHERE tpi_id = '3130'
As stated in the title, when I run this in PHP, the value is set to an empty string. However, when the exact same query is run directly in MySQL, it works correctly.
On top of that, I'm only getting this behavior on a single enum value: 'Conversion Completed'. When updating with other values (most of which also contain spaces), there is no problem.
Actual PHP code for those interested:
$sql = "UPDATE caption_queue SET status = 'Conversion Completed' WHERE tpi_id = '$tpi_id'";
$val = mysqli_query($link, $sql);
//$link comes from somewhere else, but we use it extensively throughout our website
Table definition:
CREATE TABLE IF NOT EXISTS `caption_queue` (
`tpi_id` int(11) NOT NULL,
`pid` int(6) DEFAULT NULL,
`conversion_began` datetime DEFAULT NULL,
`yt_caption_id` varchar(50) DEFAULT NULL,
`yt_video_id` varchar(50) DEFAULT NULL,
`status` enum('Pending Conversion','Converting','Conversion Completed','Pending Upload','Video Processing','Video Processed','Uploading Transcription','Caption Syncing','Caption Synced','Caption Downloading','Caption Ready') DEFAULT 'Pending Conversion'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
if you are using MySQLI and your database has enums you need to find the place of your value in order to update your database because it does not accept new strings!
here is an example of the column of my database configuration!
status enum('active', 'inactive', 'banned')
if you want to update these values convert the values into numbers for example active = 1, inactive = 2, banned = 3
from PHP we are able to do the following
$query = 'UPDATE '.$this->table.' SET status = :status'
$stmt = $this->conn->prepare($query);
if($this->status == 'active')
{
$finalStatus = 1;
}
if($this->status == 'inactive')
{
$finalStatus = 2;
}
if($this->status == 'banned')
{
$finalStatus = 3;
}
$stmt->bindParam(':status', $finalStatus);
$stmt->execute();
and this will save your day!
this code was used as an example to provide a full solution to this issue!
Thanks.
I think you'll find it should work if you put the column called status in back ticks.
$query="UPDATE caption_queue SET `status` = 'Conversion Completed' WHERE tpi_id = '3130'";
I found a workaround. By using strict mode:
SET SESSION sql_mode = 'STRICT_ALL_TABLES'
I'm able to update the field with no issues. Seems like some kind of issue with mysqli.

SQL Syntax Error when running through PHP but runs fine as an SQL Query

So, a snippet of my code which is resulting in an error is :
$con = mysqli_connect('localhost', 'root', '', 'notesDB');
if(isset($_POST['tableName'])) {
$tName = htmlentities($_POST['tableName']);
$firstQuery = mysqli_query($con,"INSERT into notes(Title) VALUES( '$tName'); CREATE TABLE $tName(id int NOT NULL AUTO_INCREMENT, Title varchar(20) NOT NULL, Description varchar(100), PRIMARY KEY(id));");
if($firstQuery){
header("Location: create2.php");
}
else
echo mysqli_error($con);
}
The output of this is :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE TABLE test1(id int NOT NULL AUTO_INCREMENT, Title varchar(20) NOT NULL, D' at line 1
Well, the funny thing is that the exact code (except the variable - I just removed the $ sign) executed perfectly in phpMyAdmin.
Also, to prove that there is nothing really wrong with the php, the query executed without any error when it was only the INSERT query (and not the CREATE query).
mysqli_query can only perform one query at a time.
Try mysqli_multi_query instead.
As an aside creating tables on the fly is usually a sign of larger design issues. Schema should be relatively static while data should be dynamic.
You are trying to run two separate queries at a time in the code, which you can't run like that. You have to run them separately like below:
$con = mysqli_connect('localhost', 'root', '', 'notesDB');
if(isset($_POST['tableName'])) {
$tName = htmlentities($_POST['tableName']);
$firstQuery = mysqli_query($con,"INSERT into notes(Title) VALUES( '$tName')");
$secondQuery = mysqli_query("CREATE TABLE '$tName' (id int NOT NULL AUTO_INCREMENT, Title varchar(20) NOT NULL, Description varchar(100), PRIMARY KEY(id));");
if($firstQuery || $secondQuery){
header("Location: create2.php");
}
else
echo mysqli_error($con);
}
Your database architecture is wrong.
You shouldn't create tables on the fly. So, you have only register whatever new entity with simple regular INSERT query. And then use this entity's id to link records from another [already existing] table.
if(isset($_POST['tableName'])) {
$stm = mysqli_prepare($con,"INSERT into notes(Title) VALUES(?)");
$stm->bind_param("s",$_POST['tableName']);
$stm->execute();
}

How to get just inserted row from MySql to a php variable?

I'm using Zend Framework and MySql to create my web-application. My SQL-code is the following at the moment:
public static function newTestResult($testId, $accountId, $score, $deviation, $averageTime)
{
try
{
$db = self::conn();
$statement = "INSERT INTO test_results(test_id, test_person_id, score, standard_deviation, average_answer_time, created_at)
VALUES(" . $testId . ", " . $accountId . ", " . $score . ", " . $deviation . ", " . $averageTime . ", NOW())";
$db->query($statement);
$db->closeConnection();
}
catch(Zend_Db_Exception $e)
{
error_log($e->getMessage());
}
}
Now what I'm asking is: How can I get the just inserted row to a variable in PHP? I would want to get my hands on the id-value what MySql is creating automatically for the row.
Here is my table code:
CREATE TABLE test_results(
id int UNSIGNED AUTO_INCREMENT PRIMARY KEY,
test_id int UNSIGNED NOT NULL,
test_person_id int UNSIGNED NOT NULL,
score float UNSIGNED NOT NULL,
standard_deviation float UNSIGNED NOT NULL,
average_answer_time float UNSIGNED NOT NULL,
removed boolean NOT NULL DEFAULT 0,
created_at datetime) CHARACTER SET utf8 COLLATE utf8_general_ci;
Take a look at the MySQL function "LAST_INSERT_ID()"
See also this forum for more detail on the methods available.
http://forums.phpfreaks.com/topic/188084-get-last-mysql-id-using-zend-frameworks/
In "plain" PHP, I usually use the mysql_ functions. The mysql_insert_id() function returns the key of the last row inserted. I'm not advocating this over using the Zend way, just giving context:
mysql_query("INSERT INTO ... query");
$id = mysql_insert_id();
Then reference that ID in writing other queries related to that inserted row.
This should give you the last insert id from the last query made.
$db->lastInsertId()
try this:
$query="SELECT id FROM test_results WHERE test_id=$testId";
$id=$db->query($query);
I assume this is what you're looking for, otherwise you can change the WHERE condition to whatever you need.
From the MySQL manual: "If you insert a record into a table that contains an AUTO_INCREMENT column, you can obtain the value stored into that column by calling the mysql_insert_id() function." This refers to the C function.
In the PHP manual, you are suggested to use the PDO function instead. http://php.net/manual/en/function.mysql-insert-id.php PDO::lastInsertId
And apparently, "The insert() method on Zend_Db_Table will return the value of the last insert id." http://osdir.com/ml/php.zend.framework.db/2007-04/msg00055.html
To get last two records from any table you can use the following query
SELECT * FROM aa WHERE ID IN(
(SELECT COUNT(*) FROM aa),
(SELECT COUNT(*) FROM aa)-1
)

IF and ELSE IF statements within a WHILE loop not working properly

I'm trying to create notification system for my community website, am trying to use a while loop to get data, when ever a condition in the if statement is met within the while loop, it should display/print data to the page. For some reason it's only displaying one result, dunno why.
The structure of my database:
CREATE TABLE IF NOT EXISTS `notifications` (
`notification_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`to_id` int(11) NOT NULL,
`notification_identifier` enum('1','2','3','4','5','6') NOT NULL,
`notify_id` int(11) NOT NULL,
`opened` enum('0','1') NOT NULL,
`timestamp` datetime NOT NULL,
PRIMARY KEY (`notification_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
The notification_identifier tell me what type of notification it is(e.g. profile comment, status update, likes) and the notify_id tells me id of each specific table i need to check with.
My code:
<?
$DisplayNotification ="";
$unread = "0";
$mynotify = mysql_query("SELECT * FROM notifications WHERE to_id='$logOptions_id' AND opened='$unread'") or die (mysql_error());
$notify_Count = mysql_num_rows($mynotify);
if($notify_Count>0){
while($row = mysql_fetch_array($mynotify)){
$notification_id = $row["notification_id"];
$memb_id = $row["user_id"];
$identifier = $row["notification_identifier"];
$notify_id =$row["notify_id"];
$timestamp = $row["timestamp"];
$convertedTime = ($myObject -> convert_datetime($timestamp));
$when_notify = ($myObject -> makeAgo($convertedTime));
if($identifier == 1){// condition 1
$DisplayNotification ='user added you as a friend';
}else if ($identifier == 2) {//condition 2
$DisplayNotification ='user commented on your post';
}
}
}else{// End of $notify
$DisplayNotification ='You have no new notifications.';
}
?>
any help appreciated
Where is $DisplayNotification actually displayed? It's certainly not within the body of your loop.
Each time through the loop you assign $DisplayNotification a new value, which of course replaces the old value. By the time you get done, no matter what's happened, the most recent change is the only one left.
Most likely I suspect you meant to do something like
$DisplayNotification .= "User added you as a friend\n";
The .= will continue adding new text to the same variable throughout the loop.
Or perhaps you could use an array, in which case you'd do
$DisplayNotifications[] = "User added you as a friend";
Then you could display all the items at the end however you'd like.
It looks like you run the while statement fully before actually dumping the variable $DisplayNotification. If that is the case, you're just switching values on the variable during the loop. You either need to store the values to be dumped inside an Array or just dump them inside the loop.

Categories