2

So I'm in the process of updating my project from an XML based schema to a mysql database one. and I'm trying to figure out how to do this function--if its at all possible. I want to fetch some rows from a Database where a value is not equal to that of a value in an array.

function catchUpgrades($id)
{
    $sql = "SELECT id, name, cost FROM upgrades WHERE prereq <> :id OR null <> :id";
    $que = $this->db->prepare($sql);
    $que->bindParam('id', $id[0]);
    try { 
        $que->execute();
        while($row = $que->fetch(PDO::FETCH_BOTH))
        {
            $array['name'] = $row[1];
            $array['id'] = $row[0];
            $array['cost'] = $row[2];
        }
    }catch(PDOException $e) {}
}
function showUpgrades()
{
    $html = "<div id='upgrades'>";
    $array = $this->getUserUpgrades();
    $upgrades = $this->catchUpgrades($array);
    print_r($upgrades);


}
user3462020
  • 63
  • 1
  • 7
  • 2
    Not an answer, but you cannot use a named parameter marker of the same name twice in a prepared statement (http://www.php.net/manual/en/pdo.prepare.php) -> `prereq <> :id OR null <> :id` – Sean Apr 02 '14 at 20:42
  • In that statement, are you saying where prereq does not equal ID, OR ID is not null? That statement makes it seems like you have a database column called `null`, which would be a problem. – larsAnders Apr 02 '14 at 20:48
  • @Sean: the PDO documentation makes it clear, can't use the same named parameter twice; when we ran into that "bug" a long time ago, I don't recall that restriction being noted in the documentation. – spencer7593 Apr 02 '14 at 21:18
  • @Sean, well that might've been part of the problem; it should've been "nullIf"... fixed that now onto the other answers! – user3462020 Apr 02 '14 at 21:27

3 Answers3

4

This predicate will never return TRUE:

OR null <> :id

NULL is a keyword representing the special "null" value. The inequality comparison to NULL will never return TRUE.

To test whether :id contains a non-NULL value, use the ANSI standard "IS NOT NULL" operator, like this:

OR :id IS NOT NULL

As a non-standard alternative, you could make use the SQL specific "null safe comparator" operator, like this:

OR NOT (:id <=> NULL)

But, it doesn't make sense that you would want to do that test, because it's redundant with the previous predicate.

What behavior do you want when the value supplied for :id is NULL? Do you want to match every row? (Your query looks familiar to the pattern we use for search criteria, where supplying a NULL value for the bind parameter disables the search criteria, like this:

WHERE ( prereq <> :id OR :id IS NULL )

If value supplied for :id is a null value, the second part will return TRUE, and it doesn't matter what first condition evaluates to at all. With a non-NULL value for :id, the second condition will be FALSE, so the first condition will need to be TRUE in order for a row to be returned.

(But that's just a guess, it's not clear what you are trying to do there.)


As another note, we ran into problems with PDO when we used the same named parameter multiple times in a statement. (The PDO documentation didn't indicate a problem with this, back when we we ran into the issue.) The workaround we used was to reference a named parameter only once in the statement, by making all of the named parameters unique.

The workaround was to do something like this:

$sql = "SELECT id, name, cost FROM upgrades WHERE prereq <> :id1 OR :id2 IS NULL";
$que = $this->db->prepare($sql);
$que->bindParam(':id1', $id[0]);
$que->bindParam(':id2', $id[0]);

(I'm not sure if that's fixed in later releases of PDO or not; it may no longer be a problem that needs a workaround like this.)

(I'm not sure that answers your question, but I gave it a shot.)

spencer7593
  • 106,611
  • 15
  • 112
  • 140
3

You can bind a value from an array. This function will work with slight changes - I added a colon, a second bound parameter with a different placeholder name to avoid a PDO conflict, and a return value. Obviously otherColumnName will have to change. If this is not what you intended, please let me know. I left a comment...

function catchUpgrades($id)
{
    $sql = "SELECT id, name, cost FROM upgrades WHERE prereq <> :id OR otherColumnName <> :id2";
    $que = $this->db->prepare($sql);
    $que->bindParam(':id', $id[0]); //note the : before id
    $que->bindParam(':id2', $id[0]); //note the : before id2
    try { 
        $que->execute();
        while($row = $que->fetch(PDO::FETCH_BOTH))
        {
            $array['id'] = $row[0];                
            $array['name'] = $row[1];
            $array['cost'] = $row[2];
        }
        return $array;
    } catch(PDOException $e) {}
}

Then, to call the function, you would have a line like this:

$results_array = catchUpgrades($id);
larsAnders
  • 3,813
  • 1
  • 15
  • 19
  • +1 For pointing out that the `':'` character was missing from the first argument to the `bindParam` method, and noting the PDO limitation of referencing a bind parameter name only one time in a statement. – spencer7593 Apr 02 '14 at 21:22
  • @spencer7593 Gracias. Chivalry is not dead! – larsAnders Apr 02 '14 at 21:26
  • So you do need to have the : before the bind? i've never had an issue with that and have been doing it sans-: with all my params to date. – user3462020 Apr 02 '14 at 21:29
  • You do need it according to [the documentation for bindParam](http://www.php.net/manual/en/pdostatement.bindparam.php). Without it, results may be unpredictable. – larsAnders Apr 02 '14 at 21:31
  • I'm trying this and for some reason it's returning an empty array. (or the array is not sticking... one of the two...) – user3462020 Apr 02 '14 at 21:35
  • Is your database handler in the global scope? If not, the function can't access it. – larsAnders Apr 02 '14 at 21:41
  • @user3462020: not clear if that colon character is required with PDO and MySQL, PDO does accept it, and all of the the examples are with the colon. The colon character is required in other interfaces/databases (e.g. Perl DBD::Oracle), but then again, DBD::Oracle also allows a named parameter to be referenced more than once too. – spencer7593 Apr 02 '14 at 21:44
-2

it's been 8 years since the question was asked, but if by chance someone else is looking for a similar question this might help

prereq != :id OR :id != null

OU:

prereq != ? OR id != ?
$que->execute([$id1, $id2]);