There is only one record in my database, and the "action_taken" column is set to NULL. How the hell do I get PDO to find it???
If I type the query directly into SQL it works as expected.
Note: This is just a test script to illustrate my problem. Most the time the value passed will be a string, but occasionally the value will be NULL.
include ('include/mysql.php');
$sql = 'SELECT * FROM returns WHERE action_taken = :action';
$sth = $dbh->prepare($sql);
$param = null;
$sth->bindValue(':action', $param, PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount())
{
echo 'FOUND YOU!';
}
else
{
echo 'NOOOO :(';
}
Basically, you can't say "equal to null". It always has to be IS null:
$sql = 'SELECT * FROM returns WHERE action_taken IS :action';
You'd be better off not using NULL at all, if at all possible.
Related
I decided to flip from mysqli/mysqlnd to PDO, however I am encountering a problem I had the last time I did this. I am trying this again as it seems that PDO allegedly supports passing a variable that contains an array of values to the execute() param for binding to the query without having to use things like call_user_func_array.
The code I have for demonstration is :
$bind_arguments[] = "dogs";
$bind_arguments[] = "cats";
$bind_arguments[] = "birds";
$db = new PDO('mysql:dbname=' . SQL_DATA . ';host=' . SQL_SERVER, SQL_USERNAME, SQL_PASSWORD, array (
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
));
$sql = 'SELECT `name` FROM `pets` WHERE `type` = ? OR `type` = ? OR `type` = ?';
$result = Array();
try {
if($stmt = $db->prepare($sql)) {
$stmt->execute($bind_arguments);
$result = $stmt->fetchAll();
}
} catch(PDOException $e) {
echo 'Wrong SQL: ' . $sql . ' Error: ' . $e->getMessage(); exit;
}
$db = null;
var_export($result); // null
I don't get any exceptions, however $result is null. If I do the regular query using Navicat (or using mysqli) It works!
See Example #5, which shows I should be able to do this (posting example from there here for reference) :
<?php
/* Execute a prepared statement using an array of values for an IN clause */
$params = array(1, 21, 63, 171);
/* Create a string for the parameter placeholders filled to the number of params */
$place_holders = implode(',', array_fill(0, count($params), '?'));
/*
This prepares the statement with enough unnamed placeholders for every value
in our $params array. The values of the $params array are then bound to the
placeholders in the prepared statement when the statement is executed.
This is not the same thing as using PDOStatement::bindParam() since this
requires a reference to the variable. PDOStatement::execute() only binds
by value instead.
*/
$sth = $dbh->prepare("SELECT id, name FROM contacts WHERE id IN ($place_holders)");
$sth->execute($params);
?>
Also see Example #1 posted below for convenience :
<?php
$sth = $dbh->prepare("SELECT name, colour FROM fruit");
$sth->execute();
/* Fetch all of the remaining rows in the result set */
print("Fetch all of the remaining rows in the result set:\n");
$result = $sth->fetchAll();
print_r($result);
?>
So why is this not working ? What am I doing wrong ?
Update
I made some typos when posting my code (which was stripped out of a larger class) for StackOverflow's MVCE requirements. These typos were not present in the original class. I have updated them in the code above. - sorry for any confusion this may have caused.
You are assigning values to $bind_array and $bnid_array but are sending in $bind_arguments to execute(). Try changing $bnid_array to $bind_array and use $stmt->execute($bind_array);
$q = $db->query(" SELECT username FROM users WHERE userident = '1' ");
echo $q; //error
print_r $q; //prints the query information (SELECT ... etc)
How do I go about getting the specific value of the element I am querying? Say the element under column username and where userident equals '1' contains the value "Patrick"; how do I initialize this string into a variable?
//same query as above
$user = $q;
echo $user; //prints "Patrick"
Sorry if this is something so rudimentary and mundane, but I've never done this outside of a foreach() loop. I'd normally iterate through rows to print specific details. The below works, but the foreach() is unnecessary as far as I understand.
foreach($q as $p) {
$user = $p["username"];
}
echo $print; //this correctly prints "Patrick"
Surely there's a method I missed somewhere?
Using the query method pretty much defeats the purpose of using prepared statements. Plus, I believe for what you're looking for, it isn't quite right.
<?php
if (!isset($_POST['id'])) {
exit;
}
$userId = $_POST['id'];
$db = new PDO(/* Stuff */);
$sql = '
SELECT username
FROM users
WHERE id = :id';
// Get a prepared statement object.
$statement = $db->prepare($sql);
// Bind a parameter to the SQL code.
$statement->bindParam(':id', $userId, PDO::PARAM_INT);
// Actually get the result.
$result = $statement->fetch(PDO::FETCH_ASSOC);
// Close the connection.
$statement->closeCursor();
// Print the result.
print_r($result);
Alternately you can use $statement->fetchAll() to gather more than one result.
Edit: I didn't actually run this code, so you might have to tinker with it to get it working right.
I am having trouble binding a null parameter in the following code
$nullVariable = NULL;
$sql = new PDO('mysql:host=' . $Server, $User, $Password);
$sql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$statement = $sql->prepare("SELECT * FROM Table WHERE Binary16Column = :uuid");
$statement->bindParam(":uuid", $nullVariable, PDO::PARAM_NULL);
$statement->execute();
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
The results variable will be a empty array. If I dont use parameters and modify my query to "WHERE Binary16Column IS NULL" it returns the expected number of rows. So the problem must be with how I am handling the parameter, rather than my SQL query.
My code is more complex than listed above, and I need to be able to use a parameter variable which may be null, so checking to see the variable is null and running a different query is less than ideal. Technically I have my own function for setting parameters, this is where I am checking if the contents of the variable is null, and binding the parameter appropriately, so I dont have to write an unnecessary number of queries. The query works also works fine if the variable contains valid data, and the parameter type is PARAM_LOB.
Does anyone know what i'm doing wrong? Thanks a lot!
Read up on three-valued logic. NULL is not a value; it is a marker for the absence of a value, and so NULL can never be equal to anything, including itself.
However, there is a null-safe comparison operator also known as the "spaceship operator," which does consider two nulls to be equivalent.
WHERE Binary16Column <=> :uuid
... should do what you expected.
If you want to select the record with Binary16Column is null, you need to use IS NULL as the condition, but not = NULL.
SELECT * FROM Table WHERE Binary16Column IS NULL
You need to do:
$uuid = /**some value**/;
$sql = new PDO('mysql:host=' . $Server, $User, $Password);
$sql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
if ($uuid === null) {
$statement = $sql->prepare("SELECT * FROM Table WHERE Binary16Column IS NULL");
} else {
$statement = $sql->prepare("SELECT * FROM Table WHERE Binary16Column = :uuid");
$statement->bindParam(":uuid", $uuid);
}
$statement->execute();
$results = $statement->fetchAll(PDO::FETCH_ASSOC);
I think the reason you are not getting a result because NULL is a keyword. Because of the way MySQL treats NULL values, I think you are going to have to do IS NULL, when you are performing a search for NULL values. I did a bunch of tests in my local database where I have NULL values. The only time that it worked is when I was using IS NULL or IS NOT NULL.
I am sorry I can't be more help (or if I'm just telling you what you already know), but it seems like you are going to have to write separate queries, or perhaps some simple logic to concatenate the appropriate WHERE logic, depending on whether a variable is null or not.
I'm learning PDO from NetTuts and have had success so far searching FETCH_ASSOC based on strings.
Question: Which PDO:: is needed in order to search by integers? I thought it was PDO::Fetch_OBJ. The following is returning false.
$busid = $this->sanitize($string);
$database->query('SELECT name, address FROM business_information WHERE id = :id', array(':id' => $busid));
var_dump($database);
if($database->count() >= '1') {
$results->setFetchMode(PDO::FETCH_OBJ);
while($row = $results->fetch()) {
$test = "Name: ".$row['name']." Address: ".$row['address'];
}else{
$test = "no results were found";
}
var_dump returns:
object(database)#1 (7) {["pdo":"database":private]=> object(PDO)#2 (0)
{ } ["port"]=> int(3306) ["statement"]=> object(PDOStatement)#6 (1) {
["queryString"]=> string(61) "SELECT name, address FROM
business_information WHERE id = :id" } }
1) Prepared statements is better than sanitizing.
2) PDO::query have another signature, read the manual please.
/** #var \PDO $PDO */
$query = $PDO->prepare('SELECT name, address FROM business_information WHERE id = :id');
if (!$query) return false;
if (!$query->execute(array(':id' => $busid))) return false;
$results = $query->fetchAll(\PDO::FETCH_ASSOC);
if (empty($results)) return false;
foreach ($results as $row)
{
$test = "Name: ".$row['name']." Address: ".$row['address'];
echo $test, PHP_EOL;
}
You may want to prepare a statement before firing it to the database. Why? The answer is somewhere near PDO::prepare. When you do use prepare, you will find yourself holding a PDOStatement as a return value.
Okey. Lets bind values to a placeholder with: PDOStatement::bindValue
Take a look at the signature:
`bool PDOStatement::bindValue(mixed $parameter,
mixed $value
[,int $data_type=PDO::PARAM_STR])`
data_type: Explicit data type for the parameter using the PDO::PARAM_* constants.
You can set data_type manually, but is not necessary in 99% of time. (As I've found it out.)
How do you check if a columns value is null? Example code:
$db = DBCxn::getCxn();
$sql = "SELECT exercise_id, author_id, submission, result, submission_time, total_rating_votes, total_rating_values
FROM submissions
LEFT OUTER JOIN submission_ratings ON submissions.exercise_id=submission_ratings.exercise_id
WHERE id=:id";
$st = $db->prepare($sql);
$st->bindParam(":id", $this->id, PDO::PARAM_INT);
$st->execute();
$row = $st->fetch();
$this->total_rating_votes = $row['total_rating_votes'];
if($this->total_rating_votes == null) // this doesn't seem to work even though there is no record in submission_ratings????
{
...
}
When you connect to the database, you can set some attributes to control how PDO handles Nulls and Empty Strings when they are returned by the database query
PDO::setAttribute (PDO::ATTR_ORACLE_NULLS, $option )
Where $option is one of the following:
PDO::NULL_NATURAL: No conversion.
PDO::NULL_EMPTY_STRING: Empty stringis converted to NULL.
PDO::NULL_TO_STRING: NULL is converted to an empty string.
Isnt it something like that that you want to do?
foreach($row as $r){
if($r->total_rating_votes == null){
//do something
}
Actually you might want to try:
if($r->total_rating_votes == ""){/*do something*/}
Because php might have converted the null value into an empty string, and then it's not actually null, it's ""
Hope this helps!
Thanks for all of your answers. After a bit of experimentation this code solved my problem
$this->total_rating_votes = $row['total_rating_votes'];
if(!isset($this->total_rating_votes)) // this is now true if this record had a NULL value in the DB!!!
{
...
}