4

I'm having trouble trying to set a variable then use it in a select statement. I keep getting a "general error" and can't figure out what I'm doing wrong. Any input would be appreciate. I'm trying to set a variable using subqueries with named parameters.

$query = $dbh->prepare("Set @available = (SELECT SUM(payments) FROM payments WHERE customer = :customer) - (SELECT SUM(charges) FROM charges WHERE customer = :customer); SELECT @available");
$query->bindParam(":customer", $customer);
$query->execute();
Ralph
  • 889
  • 14
  • 25
  • 2
    I don't think PHP allows you to run more than one SQL query at once (to prevent SQL injection attacks). – scrowler Nov 07 '13 at 00:32
  • 1
    possible duplicate of [PDO support for multiple queries (PDO\_MYSQL, PDO\_MYSQLND)](http://stackoverflow.com/questions/6346674/pdo-support-for-multiple-queries-pdo-mysql-pdo-mysqlnd) – Phil Nov 07 '13 at 00:34
  • @scowler `mysqli::multi_query()` specifically allows multiple queries and `mysqli` provides methods for returning multiple result sets. There's no support for _prepared_ multiple queries - I think that's a limitation of MySQL. One can always handle the escaping with `mysqli::real_escape_string()` –  Nov 07 '13 at 01:13
  • @scrowler 1. PHP has nothing to do with multiple queries. 2. multiple queries has nothing to do with SQL injection attacks – Your Common Sense Nov 07 '13 at 07:33
  • @your common sense - incorrect, multiple queries form the base behind many of the common SQL injection attacks, wiki it for more info – scrowler Nov 07 '13 at 10:29
  • @scrowler oh, the same relation as rosemary has to a fish. – Your Common Sense Nov 07 '13 at 11:53

2 Answers2

8

If you want to use MySQL user variables, for some reason, you don't need multi-queries support. They (user variables) live as long as you session (connection) is open. Therefore you can do something like this

$customer = 1;

try {
    $db = new PDO('mysql:host=localhost;dbname=dbname;charset=UTF8', 'user', 'password');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

    $sql = "SET @available = (SELECT SUM(payments) FROM payments WHERE customer = ?) - 
                             (SELECT SUM(charges)  FROM charges  WHERE customer = ?)";
    $query = $db->prepare($sql);
    $query->execute(array($customer, $customer));

    $query = $db->prepare("SELECT @available");
    $query->execute();
    $result = $query->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
    echo "Exeption: " .$e->getMessage();
    $result = false;
}
$query = null;
$db = null;

var_dump($result);

Sample output:

array(1) {
  [0]=>
  array(1) {
    ["@available"]=>
    string(6) "100.00"
  }
}
peterm
  • 91,357
  • 15
  • 148
  • 157
  • Why use a prepared statement for `SELECT @available`? It has no variables - a prepared statement generates an extra call to the database. –  Nov 07 '13 at 01:23
  • @MikeW I hope that OP wants to use MySQL user variables for something more meaningful than just `SELECT @variable`. Therefore this more meaningful query most likely need to be prepared. Other then that you right, there is no need to prepare just `SELECT @available`. – peterm Nov 07 '13 at 01:30
  • @Ralph Did it help? Do you need more help with your question? – peterm Nov 11 '13 at 19:19
0

PDO doesn't seem to offer any formalised support for multi-queries (but some support does seem to be available), but mysqli does. Neither offer support for prepared multiple statements, though.

You can use mysqli like this:

$mysqli = new mysqli('servername', 'username', 'password', 'dbname');
$query = sprintf("Set @available = (SELECT SUM(payments) FROM payments WHERE customer = %1$s)" .
            " - (SELECT SUM(charges) FROM charges WHERE customer = %1$s);".
            " SELECT @available",
            $mysqli->real_escape_string($customer) );

 // Following code lifted from PHP Manual.
 // This code will read multiple results, if they're available.
 // Your query only returns one.

 /* execute multi query */
 if ($mysqli->multi_query($query)) {
    do {
        /* store first result set */
        if ($result = $mysqli->store_result()) {
            while ($row = $result->fetch_row()) {
                printf("%s\n", $row[0]);
            }
            $result->free();
        }
        /* print divider */
        if ($mysqli->more_results()) {
            printf("-----------------\n");
        }
    } while ($mysqli->next_result());
}

The reference is here