Mysqli simple query: weird result using mysqli_stmt_bind_result - php

I have a mySQL table defined as:
CREATE TABLE IF NOT EXISTS `tweet` (
`user_mail` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`date_sent` datetime NOT NULL,
`date_edited` datetime NOT NULL,
`message` tinytext CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`user_mail`,`date_sent`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
And two differents entries in this table as follows:
INSERT INTO `tweet` (`user_mail`, `date_sent`, `date_edited`, `message`) VALUES
('RichardSpencer#gmail.com', '2016-01-22 14:07:45', '', 'First tweet !');
INSERT INTO `tweet` (`user_mail`, `date_sent`, `date_edited`, `message`) VALUES
('JohnDoe#gmail.com', '2016-01-22 14:07:45', '', 'Second tweet !');
I'm using this PHP function to retrieve all tweets (at this moment there are only 2 tweets) of my table 'tweet'
function getAllTweets($con, $limit){
$stmt = mysqli_prepare($con, 'SELECT * FROM tweet ORDER BY date_sent DESC LIMIT 0, ?') or die('Oups erreur dans la requète SELECT avec le message: '. mysqli_error($con));
mysqli_stmt_bind_param($stmt, 'i', $limit);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $datas['user_mail'], $datas['date_sent'], $datas['date_edited'], $datas['message']);
while($datas == mysqli_stmt_fetch($stmt)){
$result []= $datas;
}
return $result;
}
And I'm calling this function like this:
$allTweets = getAllTweets($con, 99);
When I see var_dump($allTweets);I get 2 tweets as I was especting but Both results are the same tweet . . . here is the var_dump result
array (size=2)
0 =>
array (size=4)
'user_mail' => string 'johnDoe#gmail.com' (length=17)
'date_sent' => string '2016-01-22 17:25:34' (length=19)
'date_edited' => string '0000-00-00 00:00:00' (length=19)
'message' => string 'Second tweet !' (length=14)
1 =>
array (size=4)
'user_mail' => string 'johnDoe#gmail.com' (length=17)
'date_sent' => string '2016-01-22 17:25:34' (length=19)
'date_edited' => string '0000-00-00 00:00:00' (length=19)
'message' => string 'Second tweet !' (length=14)
If you see my table I should have one tweet with the message "First tweet !"
And a second tweet with a message "Second tweet !"
Where is my mistake ?

Related

errno 1048, 'Column 'username' cannot be null'

Can you tell me why my code isn't working ? In my username table I have two columns, user_id and username. user_id is auto increment so I don't have that in my Sql statement, which I believe is the correct thing to do.
<?php
require('dbConnect.php');
$Number = $_POST['phonenumber'];
// The ? below are parameter markers used for variable binding
// auto increment does not need prepared statements
$query = "INSERT INTO user (username) VALUES (?)";
$stmt = mysqli_prepare($con,$query) or die(mysqli_error($con));
//bind variables
mysqli_stmt_bind_param($stmt,"s",$u);
//$stmt->bind_param("s",$u);
mysqli_stmt_execute($stmt);
if(mysqli_query($con,$query))
{
echo 'Inserted correctly';
}
else
{
echo 'Error';
echo var_dump($stmt);
}
mysqli_stmt_close($stmt);
mysqli_close($con);
?>
I keep getting 'Error', and in my var_dump I get :
C:\wamp64\www\phpproject\php-project\insert.php:28:
object(mysqli_stmt)[2]
public 'affected_rows' => int -1
public 'insert_id' => int 0
public 'num_rows' => int 0
public 'param_count' => int 1
public 'field_count' => int 0
public 'errno' => int 1048
public 'error' => string 'Column 'username' cannot be null' (length=32)
public 'error_list' =>
array (size=1)
0 =>
array (size=3)
'errno' => int 1048
'sqlstate' => string '23000' (length=5)
'error' => string 'Column 'username' cannot be null' (length=32)
public 'sqlstate' => string '23000' (length=5)
public 'id' => int 1
use null for autoincrement like this
$query = "INSERT INTO user (user_id,username) VALUES (null,$username)";

Weird error when using MySQL when using PDO

I encountered a very strange bug today. I am getting sideblinded by this so bad as it's breaking my entire application.
So, I have this little framework that I've built where I have a standard modell, so snippeting this will be a little long and descriptive.
<?php include('inc/inc.php'); ?>
<?php
if(!empty($_POST['answer']) && !empty($_POST['levelstart'])){
if($stmt = $site->answerQuestion($_POST['levelstart'], $_POST['answer'])){
if($stmt[0]){
echo json_encode(array('success' => true, 'correct' => $stmt[1], 'correctanswer' => $stmt[2], 'round_end' => $stmt[3]));
}else{
echo json_encode(array('success' => false, 'error' => 'error occurred'.$stmt[1]));
}
}else{
echo json_encode(array('sucess' => false, 'error' => 'Unknown error'));
}
}else{
echo json_encode(array('success' => false, 'error' => 'Provide all necessary parameters.'));
}
?>
this piece of code outputs the following.
INSERT INTO quiz_level_starts (`user_id`, `question_id`, `time`, `round_id`, `type`, `success`, `ref_id`) VALUES ('4', '10', '1471887809', '', '1', '1', '905'){"success":false,"error":"error occurred23000"}
The generated query above is only a dummy one that i simple put together so I don't need the parameterization for simply testing. The "error" key in the json array contains error data, and the errorcode is dumped there.
23000 is the mysql error code for there being a duplicate unique column, but there is no unique column that I'm using in the query(see table struct below.)
Since the function answerQuestion is a very long one, I'll only paste the related lines next. In $site->answerQuestion it calls a function called "insertLevelStarts" which is supposed to insert an entry to the db.
This is how i call it:
if($stmtss = $this->db->insertLevelStarts($_SESSION['user']['id'], $stmts['return'][0]['id'], time(), $roundid, 1, 1, $levelstart)){
And this is how it's declared, also the rest of the related and unknown code:
public function insertLevelStarts($user_id, $question_id, $time, $round_id, $type = 0, $success = 0, $refid = 0){
/*
Type=0 start 1 stop
success=0 for start 1 if successfull on stop
*/
$query = 'INSERT INTO quiz_level_starts (`user_id`, `question_id`, `time`, `round_id`, `type`, `success`, `ref_id`) VALUES (:user_id, :question_id, :time, :round_id, :type, :success, :refid)';
echo $this->genFakeQuery($query, array(
':user_id' => $user_id,
':question_id' => $question_id,
':time' => $time,
':type' => $type,
':success' => $success,
':refid' => $refid,
':round_id' => $round_id
));
return $this->execInsert($query, array(
':user_id' => $user_id,
':question_id' => $question_id,
':time' => $time,
':type' => $type,
':success' => $success,
':refid' => $refid,
':round_id' => $round_id
)
);
}
public function genFakeQuery($query, $array){
foreach($array as $key => $val){
$query = str_replace($key, "'$val'", $query);
}
return $query;
}
public function execUpdate($query, $preparray, $updatearr){
try {
$stmt = $this->db->prepare($query);
$stmt->execute(array_merge($preparray, $updatearr));
$rows = $stmt->rowCount();
if($rows > 0){
return array('type' => 'rowsaffected', 'return' => $rows);
}else{
return array('type' => 'noreturn', 'return' => 'none');
}
} catch(PDOException $ex) {
return array('type' => 'error', 'return' => $ex);
}
}
public function updateClause($query, $update, $updatearr){
if(count($update) > 0){
$count = 0;
foreach($update as $k => $v){
if($count > 0){
$query .= ',';
}
$query .= " `$k` = :$k";
$updatearr[":$k"] = $v;
$count++;
}
}
return array('query' => $query, 'updatearr' => $updatearr);
}
The aforementioned query
INSERT INTO quiz_level_starts (`user_id`, `question_id`, `time`, `round_id`, `type`, `success`, `ref_id`) VALUES ('4', '10', '1471887809', '', '1', '1', '905')
inserts into a table looking like this:
CREATE TABLE IF NOT EXISTS `quiz_level_starts` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`question_id` int(11) NOT NULL,
`time` int(11) NOT NULL,
`type` int(11) NOT NULL,
`success` int(11) NOT NULL,
`ref_id` int(11) NOT NULL,
`round_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `quiz_level_starts`
ADD PRIMARY KEY (`id`);
ALTER TABLE `quiz_level_starts`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
Will greatly appriciate any help recieved.
I assume that the error occurs because round_id is an integer field that can not be NULL and has no default value and you pass it an empty value.
Try if this query works:
INSERT INTO quiz_level_starts (`user_id`, `question_id`, `time`, `round_id`, `type`, `success`, `ref_id`) VALUES ('4', '10', '1471887809', '0', '1', '1', '905')

This String Variable Always Gives Me Zero When Inserted In MySQL

I have this PHP function :
public function addInvoice ($order_id, $invoice_id, $product_id, $product_quantity, $product_price, $product_reseller_fee,
$product_reseller_poin, $product_referral_fee, $product_referral_id,
$product_vendor_sales, $custom_invoice){
$this->connect();
$this->select('shopping_cart', 'courier_cost', NULL, 'product_id = "'.$product_id.'" AND order_id = "'.$order_id.'"', NULL, '1');
$ongkir = $this->getResult();
$ongkir = $ongkir[0]['courier_cost']; //-- this gives me ZERO when inserted into MySQL
$product_vendor_income = ($product_vendor_sales * $product_quantity) + $ongkir; //-- $ongkir in this formula also count as ZERO
$data = array ('order_id' => $this->escapeString($order_id),
'invoice_id' => $this->escapeString($invoice_id),
'product_id' => $this->escapeString($product_id),
'product_quantity' => $this->escapeString($product_quantity),
'product_price' => $this->escapeString($product_price),
'product_reseller_fee' => $this->escapeString($product_reseller_fee),
'product_reseller_poin' => $this->escapeString($product_reseller_poin),
'product_referral_fee' => $this->escapeString($product_referral_fee),
'product_referral_id' => $this->escapeString($product_referral_id),
'product_vendor_sales' => $this->escapeString($product_vendor_income),
'custom_invoice' => $this->escapeString($custom_invoice));
$this->insert('sales_invoice', $data);
$res = $this->getResult();
return $res;
}
$ongkir variable result is string(4) "6000" when I do var_dump. so, I believe it's a string.
on the other side, I have a MySQL colum which has Decimal data type. when I tried to insert $ongkir into database, it ends up with zero.
do I have to convert this string into numeric data type? that's odd...
I tried to show on the screen what's the value of $ongkir :
$ongkir = $product->addInvoiceCopy ('ORD - 5762 5CF0 BFB9 6', null, '801', '1', null, null, null, null, null, null, '22000', null);
$total = (100 * 2) + $ongkir;
var_dump($total);
it produce :
int(6200)
so, $ongkir is not an empty variable or zero. but why I get zero when inserted into MySQL? any clue? thank you.

Cakephp 2.0: complex find query

I'm trying to pull some info out of two tables linked by the hasMany and belongsTo associations.
requisitions hasMany locations and locations belongsTo requisitions
TABLE `requisitions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`fecha_generacion` date NOT NULL,
`solicitado_a` varchar(60) NOT NULL,
`proyecto` varchar(150) NOT NULL,
`obra_no` varchar(11) NOT NULL,
`observaciones` text NOT NULL,
PRIMARY KEY (`id`)
)
and
TABLE `locations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`requisition_id` int(11) NOT NULL,
`fecha` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`name` enum('pendiente','tecnico','existencia','cotizando','generar_o','archivada')
NOT NULL DEFAULT 'pendiente',
`image_path` varchar(150) NOT NULL DEFAULT 'estado0.png',
`note` text NOT NULL,
PRIMARY KEY (`id`)
)
Requisition goes from one Location to another and I need to keep track of its current Location looking by a given Location as 'pendiente','tecnico'...
So I need to generate a list with the last Location for each Requisition and then filter that list by the Location.name
I believe the only way to do this is with a query around another query, so I'm trying to understand cakephp syntax with more simple queries first.
I was trying to search for the last 'pendiente' Location with the next code from my RequisitionsController.
$lastPendiente = $this->Requisition->Location->find('all', array(
'conditions' => array('Location.name' => 'pendiente'),
'fields' => array('MAX(Location.id) AS olderLocation', 'Location.requisition_id'),
'group' => 'Requisition.id',
));
I have the query
SELECT MAX(`Location`.`id`) AS olderLocation, `Location`.`requisition_id` FROM `petrofil_demo`.`locations` AS `Location` LEFT JOIN `petrofil_demo`.`requisitions` AS `Requisition` ON (`Location`.`requisition_id` = `Requisition`.`id`) WHERE `Location`.`name` = 'pendiente' GROUP BY `Requisition`.`id`
output...
array(
(int) 0 => array(
(int) 0 => array(
'olderLocation' => '22'
),
'Location' => array(
'requisition_id' => '29'
)
),
(int) 1 => array(
(int) 0 => array(
'olderLocation' => '5'
),
'Location' => array(
'requisition_id' => '30'
)
),
(int) 2 => array(
(int) 0 => array(
'olderLocation' => '13'
),
'Location' => array(
'requisition_id' => '31'
)
)
)
...which is great because those are exactly the last requisitions with a 'pendiente' location but here comes the second query or the condition where I'm clueless. I need to be sure my requisition last state was 'pendiente' and not another possible locations. For example my requisition_id =>30 last location is really 'tecnico' so I need to find a way to exclude it from showing on my results.
You could quit the condition from the query, put the 'name' column in the 'fields' and add an order by sentence:
$lastPendiente = $this->Requisition->Location->find('all', array(
'fields' => array('MAX(Location.id) AS olderLocation', 'Location.requisition_id', 'name'),
'group' => 'Requisition.id',
'order' => 'fecha DESC'
));
This way you only get the last status from the Location table. Then, you could iterate the results, filtering by the 'name' column and deleting those whit a 'name' diferent from 'pendiente':
foreach($lastPendiente as $k => $location){
if($location['Location']['name'] != 'pendiente'){
unset($lastPendiente[$k]);
}

How do I elegantly retrieve DB data with a one-to-many?

I'm querying against a database to retrieve some information that includes a one to many relationship. Consider:
CREATE TABLE `movies` (
`id` int(10) unsigned NOT NULL auto_increment,
`title` varchar(50) NOT NULL,
`desc` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `movies` VALUES ('1', 'The Princess Bride', 'A fantastic film of epic adventure, action, and love.');
CREATE TABLE `showtimes` (
`movie_id` int(10) unsigned NOT NULL,
`showtime_id` int(10) unsigned NOT NULL auto_increment,
`starttime` timestamp NOT NULL,
PRIMARY KEY (`movie_id`,`showtime_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `showtimes` VALUES ('1', '1', '2011-09-19 20:00:00'), ('1', '2', '2011-09-19 23:00:00'), ('1', '3', '2011-09-20 13:00:00');
The way I'd like to receive the information is something like this.
$movies[1] = array(
'id' => 1,
'title' => 'The Princess Bride',
'desc' => 'A fantastic film of epic adventure, action, and love.',
'showtimes' => array(
'1' => '2011-09-19 20:00:00',
'2' => '2011-09-19 23:00:00',
'3' => '2011-09-20 13:00:00'));
This seems to be the most sensible way for me to go through the data. If I'm printing all the showtimes for the theatre, I can do something simple like:
foreach($movies as $movie)
{
//pretend there's style stuff here
echo $movie['title'] . "&mdash" . $movie['desc'];
foreach($movie['showtime'] as $time)
{
if ($time > $_SERVER['REQUEST_TIME'])
{
echo $time;
}
}
}
Unfortunately, that's not what I get back from a standard query. Something like:
SELECT * FROM `movies` INNER JOIN `showtimes` ON `movies`.`id` = `showtimes`.`movie_id`;
Yields:
$movies[1] = array('id' => 1, 'title' => 'The Princess Bride', 'desc' => 'A fantastic film of epic adventure, action, and love.', 'starttime' => '2011-09-19 20:00:00');
$movies[2] = array('id' => 1, 'title' => 'The Princess Bride', 'desc' => 'A fantastic film of epic adventure, action, and love.', 'starttime' => '2011-09-19 23:00:00');
$movies[3] = array('id' => 1, 'title' => 'The Princess Bride', 'desc' => 'A fantastic film of epic adventure, action, and love.', 'starttime' => '2011-09-20 13:00:00');
which isn't quite what I'm going for. In larger result sets with more data I'm also mildly curious about the effect of returning so much duplicated data (consider wider rows with tens of joins).
I know I can use a construct like GROUP_CONCAT() to append those showtimes together, but I'm left splitting them apart later. For simple things like timestamps it's easy as I can choose a delimiter that wont appear in that format, if I was splitting reviews for example it would be a bit tougher.
I can do something lame like iterate over all the movies, querying showtimes from within that loop, but there's no way that will ever be web scale.
I can execute the join in-query, then iterate over those results and append on duplicate primary key, but that seems to lack elegance as well.
The Question
Is there an elegant way to get what I'm looking for? On this particular application I'm using Zend Framework, if it's built into that (or another framework) that would be pretty keen.
thanks
Do some kind of join (your choice) on the two tables and then loop through the results.
$query = "SELECT * FROM movies LEFT JOIN showtimes ON showtimes.movie_id = movies.id";
$result = $db->query($query);
while($row = $result->fetch()){
if(isset($movies[$row['id']])
$movies[$row['id']]['showtimes'][] = $row['starttime'];
else{
$movies[$row['id']] = array(
'id'=>$row['id'],
'title'=>$row['title'],
'desc'=>$row['desc'],
'showtimes'=>array($row['starttime'])
);
}
}

Categories