I've spent 2 days trying to fix this - my date comparisons in MySQL aren't working when
trying to bind values with the <= less than or equals operator.
I've narrowed it down to the second date field (from a much more complicated script that changes the prepared statement joins/groups/fields/conditions depending on the request..hence why I am referring to table.column and selecting from only one table below - it works either way) but I can't make sense of it. The exact code used to work on php 5.x but I have just upgraded to php7.2.27.
Take the below SQL statement:
$sth = $this->prepare("SELECT
transaction.transactionid,
transaction.accountid,
transaction.userid,
transaction.billdate,
transaction.amount,
transaction.description,
transaction.confirmed
FROM transaction
WHERE
DATE(`billdate`) BETWEEN :startdate AND :enddate #date('2020-03-12')
ORDER BY billdate desc");
Trying to bind the following to it:
$terms = array(':startdate' => "2000-01-01",':enddate' => "2020-03-12");
foreach ($terms as $key => $value) {
if($value == (int)$value)
$sth->bindValue("$key", $value, PDO::PARAM_INT);
else
$sth->bindValue("$key", $value);
}
var_dump($sth);
var_dump($terms);
$sth->execute();
$this->rowCount = $sth->rowCount();
var_dump( $sth->fetchAll(PDO::FETCH_ASSOC));
This returns an empty array.
The table contains a handful of test rows. The below returns correctly:
...
DATE(`billdate`) BETWEEN :startdate AND '2020-03-12'
ORDER BY billdate desc
Wrapping the dates in date('date') seems to make no difference.
I've also tried this...
DATE(`billdate`) >= :startdate AND
DATE(`billdate`) <= '2020-03-12'
ORDER BY billdate desc
");
(Of course, changing the bound terms so that they mirror whatever I am using)
I need to be able to bind both variables.
Grateful for any pointers as I would love to avoid wasting another day debugging this!
Thanks
Just CAST to DATE:
WHERE billdate
BETWEEN CAST(:startdate AS DATE) AND CAST(:enddate AS DATE)"
And bind as PDO::PARAM_STR:
$sth->bindValue("startdate", "2000-01-01", PDO::PARAM_STR);
$sth->bindValue("enddate", "2020-03-12", PDO::PARAM_STR);
Related
I'm still struggling to find out the best possible solution for binding one date as variable in SQL with PDO. So far I programmed a function in PHP which approximates times in a specific date. I only have one date but the dirtiest solution which I found would be to bind it twice which I wouldn't risk to keep my code clean. So I was thinking to set a variable which will be used then in Where Clause. That's my code so far:
<?php
function approximateAppo($date){
$link = OpenDB();
try {
$query = "SET #v1 = :date;
SELECT from, till
FROM termin
WHERE from >= CONVERT('#v1 08:00:00', DATETIME)
AND till <= CONVERT('#v1 20:00:00', DATETIME)
AND comp_id=:comp";
$statement = $link->prepare($query);
$statement->bindValue(':comp', $_SESSION['comp'],PDO::PARAM_INT);
$statement->bindValue(':date', $date, PDO::PARAM_STR);
$statement->execute();
$row = $statement->fetchAll();
} catch (PDOException $e){
p($e);
}
CloseDB($link);
return $row;
}
But it doesn't really work, what might be the issue in there? Or what is the best possible solution for solving the issue? I still haven't found anything similar for solving my case.
You can't execute multiple queries in a single call.
You can initialize a variable in a subquery.
Also, variables aren't replaced inside strings, you need to use CONCAT().
$query = "SELECT from, till
FROM termin
CROSS JOIN (SELECT #v1 := :date) AS x
WHERE from >= CONVERT(CONCAT(#v1, ' 08:00:00'), DATETIME)
AND till <= CONVERT(CONCAT(#v1, ' 20:00:00'), DATETIME)
AND comp_id=:comp";
But there isn't really a need for the variable, you can use the :date placeholder twice.
$query = "SELECT from, till
FROM termin
WHERE from >= CONVERT(CONCAT(:date, ' 08:00:00'), DATETIME)
AND till <= CONVERT(CONCAT(:date, ' 20:00:00'), DATETIME)
AND comp_id=:comp";
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);
probably a simple case. Basically I have a Database with 5 fields, which are showing Orders and their progress:
idRefs, Quantity, refsDone, refsRunning, refsUntouched
Now I want to select all those Rows, where Quantity = refsDone (this means the order is done). I am wondering how I can do this using PDO ? This is what I've tried:
$filter = $_POST['filter'];
$limiter = $_POST['limiter'];
$refid = $_POST['refid'];
if($refid == "") $refid="%";
case("finished"):
$sql = "SELECT * FROM Orders WHERE REFID LIKE :refid AND quantity=refsDone ORDER BY dateAdded DESC LIMIT :min,:max";
$ps_orders = $db->prepare($sql);
$ps_orders->bindParam(':refid', $refid, PDO::PARAM_STR);
$ps_orders->bindParam(':min', $min, PDO::PARAM_INT);
$ps_orders->bindParam(':max', $limiter, PDO::PARAM_INT);
$ps_orders->execute();
$rowCount = $ps_orders->fetchColumn();
$data = $ps_orders->fetchAll();
break;
Cant say whats happening wrong, but I am kinda sure it is the part "AND quantity=refsDone" which causes it.
I tested your query in this SQLFiddle: http://sqlfiddle.com/#!2/32ae40/8
The query returns an empty set in several cases:
if $refid is null
if $refid is empty string ('')
if $min is 1 or more
if $limiter is 0
I think you should make sure your variables are values you expect them to be, because if they aren't the query is likely to return an empty set.
You can troubleshoot parameterized queries yourself by enabling the MySQL general query log, which logs both the prepared query and the query with parameter values included.
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.
I recently heard that soon PHP will be deprecating all of the traditional mysql functions (ex: mysql_query(), mysql_num_rows(), etc...). That being said, I'm trying to convert all of my queries into PDO format. This one particular case is giving me some difficulty,
$team = $_GET['team'];
$ncaa = array("Duke", "Harvard", "Yale", "Stanford");
$limit = idate('z')+14;
$list = join("','", $ncaa);
$query = "SELECT game_id
FROM ncaa_current_season_games
WHERE game_date_int >= :game_date_int
AND (home_team = :team OR away_team = :team)
AND home_team IN(:list)
AND away_team IN(:list)
ORDER BY game_date_int ASC
LIMIT 1";
$stmt = $db->prepare($query);
$stmt->execute(array(':game_date_int' => $limit, ':team' => $team, ':list' => $list));
$num = $stmt->rowCount();
$num is returned as 0. When I had the query in my old format (not PDO), it worked just fine.
Any suggestions?
Thanks,
Lance
You can't use the :list as one placeholder for the in clause, you need one placeholder for one value.
PDO, as any other raw API, is insufficient for the any real-life task.
And prepared statements are insufficient too, as they accept only scalar data, not whatever complex data types or arbitrary query parts.
So, a developer have to help himself with adopting a database abstraction library.
And use this library methods in their application code instead of raw API calls.
With raw PDO you need to create ? mark for the every IN statement value dynamically, using str_repeat() function or something of the kind, add every value to the data array, and then run all that train.
You can find plenty of examples on this site. Some of them are quite smart though.
But with good database access library, you can do it the way you tried (in vain) with raw PDO
$team = $_GET['team'];
$ncaa = array("Duke", "Harvard", "Yale", "Stanford");
$limit = idate('z')+14;
$query = "SELECT game_id
FROM ncaa_current_season_games
WHERE game_date_int >= ?s
AND (home_team = ?s OR away_team = ?s)
AND home_team IN(?a)
AND away_team IN(?a)
ORDER BY game_date_int ASC
LIMIT 1";
$data = $db->getRow($query, $limit, $team, $team, $list, $list);