PDO query returning 0 - php

I'm trying to execute a query one is working and one isn't
Code:
$sth = $this->_pdo->prepare("SELECT * FROM `messages` WHERE `service_id` = :service AND `created` > (NOW() - INTERVAL 7 DAY) LIMIT 1, :limit");
$leng = $this->_settings->length;
$sth->bindParam(":service", $this->_settings->service, PDO::PARAM_INT);
$sth->bindParam(":limit", $leng, PDO::PARAM_INT);
$sth->execute();
$component_data = $sth->fetchAll(PDO::FETCH_OBJ);
var_dump($component_data);
echo values : SELECT * FROMmessagesWHEREservice_id= 3 ANDcreated> (NOW() - INTERVAL 7 DAY) LIMIT 1, 5 this query isn't working
and this one is: SELECT * FROMmessagesWHEREservice_id= 2 ANDcreated> (NOW() - INTERVAL 7 DAY) LIMIT 1, 5
If I execute the first one inside my database editor tool I get this as result:
Why isn't the first query returning anything? and why is the second query returning something? even though they're the same?

I'm not spotting any specific error.
But the first suspect on the list is the bindParam. For debugging, I'd try using a scalar, and also echo out the value.
$service_param = $this->_settings->service;
var_dump($service_param);
$sth->bindParam(":service", $this->_settings->service, PDO::PARAM_INT);
For debugging, I'd also try removing the bind placeholder for LIMIT, and hardcoding that in the statement.
Since there's no check of the return from the "prepare" and "execute" functions, so I'm going to assume that the PDO error mode is set to throw an exception if a database error occurs. That is, I'm assuming that the database connection has these attributes set:
$this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

I spot various mistakes.
1: (deleted ignore)
2: Your limit clause should be 0,something. Putting a 1 there makes it skip 1 record.

Related

Looping a sql statement if more than 1 record found

I'm trying to check if a certain record meet the following condition: status is "File Closed", not_visible = "0" and status_date is earlier by 14 days or more.
If condition met, to update not_visible "0" to "1".
This is invoke whenever a user logs in.
Problem:
The sql only run once even if 10 records found. How do I loop it to complete updating all records found and exit the statement once done?
global $conn;
$strSQLExists = "select lead_id as a, status_date as b, not_visible as c from tbl_progress where status = 'File Closed' and not_visible = '0' and status_date <= DATE_ADD(CURDATE(), INTERVAL -14 DAY) ";
$rsExists = db_query($strSQLExists,$conn);
$data=db_fetch_array($rsExists);
if($data)
{
$sql = "UPDATE tbl_progress SET not_visible = '1' WHERE lead_id = '".$data["a"]."'";
CustomQuery($sql);
return false;
}
else
{
// if dont exist do something else
}
Was adviced to just update:
so here we are:
UPDATE tbl_progress SET not_visible = '1' WHERE status = 'File Closed' and not_visible = '0' and status_date <= DATE_ADD(CURDATE(), INTERVAL -14 DAY)
Doing it using update statement only (as per your edit) should fix the issue. Actually, using update fixes
the looping issue, as it updates all records that match, not just one
the sql injection issue, as there are no parameters passed around and no string concatenation of the sql statement
the race condition issue that might occur if something was changed between select and update
It will also be slightly more efficient, as it pushes the logic to db.
In short: using an update instead of select + update will fix the looping issue and some other issues you didn't know you had, so use that.

MySQL PDO, selecting a single row from a result-set

If I run a query that returns multiple rows, is there a way I can select just one row out of that result?
So if I do something like
SELECT * FROM table WHERE number = 10
and it returns 33 results, is there a way I can go through those one at a time instead of returning the whole result set at once, or just return, for example, row 5 of the result set?
I have read about scrollable cursors but it seems they don't work on MySQL, although that seems to be what I am looking for....
I am using PDO with MySQL and PHP. I hope this makes sense, if not I will try and explain better.
Edit: This worked for what I wanted. Thanks.
$stmt = $dbh->prepare("SELECT * FROM $table WHERE user_points = '$target' ORDER BY tdate DESC LIMIT $count,1");
is there a way I can select just one row out of that result?
Yes there is, you can use LIMIT:
SELECT * FROM table WHERE number = 10 LIMIT 1;
$sql= "SELECT * FROM $table WHERE user_points = '$target' ORDER BY tdate";
$stmt= $pdo -> prepare($sql);
$stmt->execute();
$data = $stmt ->fetchAll();
//You asked about getting a specific row 5
//rows begin with 0. Now $data2 contains row 5
$data2 = $data[4];
echo $data2['A_column_in_your_table'];//row 5 data

PHP PDO rowCount returns -1 on SELECT statement

I am having a strange problem that has been kicking my backside all day long.
I have the following code:
$today = date("m/d/Y");
$sql = "SELECT * FROM msgs WHERE is_errata = 0 AND kill_date >= '$today' AND msg_date <= '$today' ORDER BY msg_date";
$ps = $pdo->prepare($sql);
if (!$ps) {
echo "PDO::errorInfo():";
print_r($pdo->errorInfo());
}else{
$ps->execute();
$number_of_rows = $ps->rowCount();
When I display the value of $number_of_rows, it ALWAYS displays -1, even when I get results.
Anyone else have this problem?
Oh, and the database I am using is NOT MySQL, but the lovely MS Access. I suspect this might be the problem.
rowCount() method does NOT return number of rows from SELECT statement. It's common mistake.
PDOStatement::rowCount() returns the number of rows affected by the
last DELETE, INSERT, or UPDATE statement executed by the corresponding
PDOStatement object.
If the last SQL statement executed by the associated PDOStatement was
a SELECT statement, some databases may return the number of rows
returned by that statement. However, this behaviour is not guaranteed
for all databases and should not be relied on for portable
applications.
More details you can find in the documentation.
So to get number of rows you have to write SELECT statement with sql COUNT(*) function. In your case:
$sql = "SELECT COUNT(*) AS `count` FROM msgs WHERE is_errata = 0 AND kill_date >= '$today' AND msg_date <= '$today' ORDER BY msg_date";
or using PHP:
$number_of_rows = count($ps->fetchAll());
You should also learn to prepare the query the right way
You should use iterator_count to count rows, i.e.
$number_of_rows = iterator_count($ps);

PHP PDO Query returning an empty array when using bindParam

Kind of stumped by this one. I have been developing for about a week now, maybe two so it might be a noob mistake, but here is what I have:
<?php
$msDB = new PDO('odbc:Driver={SQL Server Native Client 11.0};Server=SOMESERVER;Trusted_Connection=yes;');
try{
//set values for query
$s="4";
$d1="'2014-10-01 00:00:00'";
$d2="'2014-10-31 23:59:59'";
//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (t1.SELECTION = :s)
AND (tN.RESPONSE_DATE BETWEEN :d1 AND :d2))";
//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->bindParam(':s',$s, PDO::PARAM_INT);
$tbe->bindParam(':d1',$d1, PDO::PARAM_STR);
$tbe->bindParam(':d2',$d2, PDO::PARAM_STR);
//execute query
$tbe->execute();
//fetch resulting data
$res = $tbe->fetchAll(PDO::FETCH_ASSOC);}
//error handling
catch (PDOException $e) {
throw new pdoDbException($e);
}
//print the resulting array
print_r($res);
//set initial count
$cnt=0;
//loop through and increment count
foreach($res as $key=>$value){
foreach($value as $v2 ){
$cnt++;
}
}
//return count value
echo "Total:<br/>".$cnt."<br/>";
?>
I am expecting this to return a result set of the number 3. And when I specify the values in the query manually, everything works as expected and it returns the number 3.
If I however use the bindParam method it returns nothing and throws no errors of any sort. It simply returns an empty array.
I can also break up the query set in $q1 and concatenate the values into it, and it also works flawlessly. I have not really used bindParam before, but as far as I can tell, I am using it correctly.
Works:
//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (t1.SELECTION = ".$s.")
AND (tN.RESPONSE_DATE BETWEEN ".$d1." AND ".$d2."))";
When I run the query in MSSQL Server Management Studio, it also returns the result set I expect.
Can anyone tell me what I am doing wrong?
The default data type passed by PDO::bindParam and PDO::bindValue is ALWAYS text. Conversion from datatype text in MSSQL is only possible to CHAR, VARCHAR, NCHAR, and NVARCHAR. It is because of the datatype issue that the value has to be converted from text into CHAR or VARCHAR and then into DATETIME from there. This is however an implicit conversion, and depending on the value passed to the query, may result in rounding errors, truncation, or simply a failed conversion.
This, does NOT work:
//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (tN.RESPONSE_DATE BETWEEN :d1 AND :d2))";
//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->bindParam(':d1',$d1, PDO::PARAM_INT);
$tbe->bindParam(':d2',$d2, PDO::PARAM_INT);
This however, does work:
$q1 = 'SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (tN.RESPONSE_DATE BETWEEN CONVERT(datetime,CONVERT(VARCHAR(MAX),?))
AND CONVERT(datetime,CONVERT(VARCHAR(MAX),?))))';
//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$tbe->bindParam(1,$d1);
$tbe->bindParam(2,$d2);
Even if I casted the bound parameters as type INT, they were still passed to MSSQL as text causing the failure.
It would be my suggestion however to simply use the original workaround of just passing in the variables directly like so and have the variables be double quoted strings:
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (t1.SELECTION = '$s')
AND (tN.RESPONSE_DATE BETWEEN '$date1' AND '$date2'))";
The quoted string is much easier to handle, and far less prone to error because it need not be converted at all and is simply passed right along to MSSQL Server without issue.
I noticed a slight performance hit with the converts because of the extra processing by MSSQL Server. The query took about half a second longer to run with the conversion than without.
Cheers to #meda for helping with the resolution!
I get this error today and take a lot of my hours.
After upgrading PHP Version to PHP7, using sqlsrv:database driver instead of dblib:dbname make this problem occurs.
To avoid this, still using dblib:dbname event PHP7 FPM already support with sqlsrv:database driver.

PHP query time() form mysql

I want that my PHP checks if the time in the mysql db is the same, and if not that it will be changed.
This is what I got:
<?php
$last_time_check=mysqli_query($con,"SELECT `time` FROM `servervars`");
if((time()-$last_time_check) >=1)
{
mysqli_query($con, 'UPDATE `servervars` SET `time`='.$time.' WHERE ID=1');
}
?>
$con is the connection to the DB.
Current value 'time' in servervars: 1412448339
Value 'ID' is 1
I do something wrong, but I just cannot find where it's going wrong.
The Fix
I've removed the variable $last_time_check and only checked if the time could get changed. If this happends then it will send another message to the client.
mysqli_query($con, 'UPDATE `servervars` SET `time` = UNIX_TIMESTAMP() WHERE ID = 1 AND UNIX_TIMESTAMP() - `time` >= 1');
if ($con->affected_rows)
{
// at least 1 second has elapsed, do stuff
}
MySQL has an equivalent to time(), its the function UNIX_TIMESTAMP(). Differently though, it can take a DATETIME as parameter to convert it into UNIX time, but when used without parameters its the same as UNIX_TIMESTAMP(NOW()).
UPDATE servervars SET time = UNIX_TIMESTAMP() WHERE ID = 1
Update
Ok so about the other issues. You are doing it all wrong. mysqli_query does not return the value directly. To fetch the value of time from the database, you need 3 steps:
$result = $con->query('SELECT `time` FROM `servervars` WHERE ID = 1'); // fetch result set
$row = $result->fetch_row(); // fetch a row from the result set, as an array
$last = $row[0]; // get the first element from the row you just fetched
Notice $con->query() can fail if theres a problem with the connection, the database, the table, or the query syntax itself, and $result->fetch_row() can fail if there are no results for the query. You should validate them before proceeding to the next step.
Alternatively, you can do this:
$con->query('UPDATE `servervars` SET `time` = UNIX_TIMESTAMP() WHERE ID = 1 AND UNIX_TIMESTAMP() - `time` >= 1');
if ($con->affected_rows)
{
// at least 1 second has elapsed, do stuff
}
This way we shortened your solution to a single query, that updates the field if necessary and report back that it happened or not..

Categories