I notice that these two ways of structuring a query with PHP PDO, both return the same data.
//prepare with $dbh->prepare
$w_ft = "36";
$sth = $dbh->prepare("SELECT * FROM main_products_common_dimensions WHERE w_ft = :w_ft");
$sth->bindParam(':w_ft', $theId, PDO::PARAM_INT);
$sth->execute();
$result = $sth->fetchAll(); //PHP array of data
//prepare with pg_prepare()
$result = pg_prepare($con, "my_query", 'SELECT * FROM main_products_common_dimensions WHERE w_ft = $1');
$result = pg_execute($con, "my_query", array("48")); //A query result resource on success or FALSE on failure.
while ($row = pg_fetch_assoc($result)){
echo $row['w_ft'] . "<BR>";
}
I read at http://php.net/manual/en/function.pg-execute.php that the second way returns "A query result resource on success or FALSE on failure." So I tried to iterate through it with pg_fetch_assoc(). It works, but is that not deprecated along with the rest of the pg_sql functions? Should I be using something in the PDO to look at the results of the query?
For this reason, I'm inclined to use the first method while using PDO. Is this the norm?
My question is how to submit multiple values to either method. Neither method works when I try to submit an array to the prepared statement
$w_ft = array("48", "36");
$result = pg_execute($con, "my_query", array("48", "36"));
I thought that I was able to submit multiple values to the query in this way. How can I do this?
Thank you
Looks like you're taking execute array wrong.
It takes values not for the consequent executions but for one execution only.
So, number of values should be equal to number of placeholders.
So it goes
$sql = 'SELECT * FROM table WHERE w_ft = $1 OR w_ft = $2 OR w_ft = $3'
for your array("48", "36", "12")
I am not a PG user though, so, I can confuse some syntax.
PDO is an agnostic database access API for PHP. This means, whatever your database is, you will be able to use the same objects and methods to query it and fetch results. PDO was the first step toward database abstraction layers in PHP.
The pg_* API is, afaik, not going to be deprecated and is dedicated to Postgres. It also contains functions that were not implemented in PDO (like binary escaping or event notifier functions amongst others).
The choice between PDO and dedicated library is often hidden by the choice of the Model Manager you use in your controllers code. Either it can be Object Relational Mapper over an abstraction layer like ORMs (Doctrine, Propel and many others) or it can be an Object Model Manager (OMM) dedicated to Postgresql like Pomm.
In both ways, you do not need to prepare statements, manage the columns types nor results cursors (btw, using PDO::fetch_all() will dump all results in memory), the database layer handles that for you. Your above query would be written like:
// Using Pomm
// SELECT * FROM main_products_common_dimensions WHERE w_ft = ?
// Returns a MainProductsCommonDimensions instance
$object = $connection
->getMapFor('\Database\Schema\MainProductsCommonDimensions')
->findWhere('w_ft = ?', array(48))
->current(); // fetch only the first result.
Note that both ORMs and OMMs do propose handy query builder:
$where = \Pomm\Query\Where::createWhere('w_ft = ?', array(48))
->orWhere('w_ft = ?', array(12))
->orWhere('w_ft = ?', array(66));
// which is pretty much the same as
$where = \Pomm\Query\Where::createIn('w_ft', array(48, 12, 66));
// SELECT * FROM main_products_common_dimensions WHERE w_ft IN (?, ?, ?);
$collection = $connection
->getMapFor('\Database\Schema\MainProductsCommonDimensions')
->findWhere($where); // Return an Iterable cursor over results
// display 48, 12 and 66 fetching one result at the time in memory:
foreach($collection as $object)
{
printf("W_FT = '%d'.\n", $object['w_ft']);
}
Using those layers above PDO offers numerous advantages, the main one is to focus more on what you want instead of dealing with weird APIs (yes PDO is weird as almost any lib in PHP). Furthermore, since PDO is just an access layer it will return results as arrays of strings (binary or not). Boolean in Postgres are 't' and 'f' and thus will need to be converted to PHP proper Boolean (sic) type to be used. ORMs and OMMs do propose such translation mechanisms and Pomm as being dedicated to Postgres also support Arrays, HStore, LTree, geometric and composite types conversions and more.
Related
I want to migrate a site from some poorly written MySQLi to clean PDO.
I have looked at three similar questions and their answers, and this is a straightforward question, but none of them are giving me results. Here's my code:
$state = "Alaska";
//trying to implement PDO here
$sql = "SELECT * FROM sales WHERE state = ? ORDER BY type";
$result = $conn->prepare($sql);
$result->execute(array($state));
/*
this was the old, successfully working way before
$sql = "SELECT * FROM sales WHERE state = '$state' ORDER BY type";
$result = $conn->query($sql);
*/
Previous questions on this site show me answers that look like my PDO implementation, yet mine doesn't work. I have made sure the PDO class exists and that the extension is loaded.
If you see the error, let me know!
The difference between the two, aside from difference in libraries, is that one is using a direct query() (the mysqli_*), while the other is using a prepared statement. Those are handled a bit different, regardless which API is running.
When using MySQLi, doing
$result = $conn->query($sql);
would have $result be a mysqli-result object, which holds the data. You can use mysqli_result::fetch_assoc() on that to fetch the data. However, when you're using PDO::prepare(), your $result variable will be a PDOStatement - which is a bit different. You'll need to run a fetch() method on it first, and then you can use the return-value of it, as such
$state = "Alaska";
$sql = "SELECT * FROM sales WHERE state = ? ORDER BY type";
$stmt = $conn->prepare($sql);
$stmt->execute(array($state));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
Note that I've changed the names of your variables. Now $result is an array (if there are any results fetched), which you can use as you normally do when fetching associative-arrays. If there are no results, PDOStatement::fetch() will return a boolean false.
var_dump($result['state']);
You can loop the fetch() method as
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
if you expect more than one row. Use $result as you would without looping, as shown above.
Note that this assumes a valid PDO-connection. Beware that you cannot interchange any MySQL libraries, mysql_, mysqli_* and PDO are all different animals in the zoo.
PHP.net on PDOStatement::fetch()
Can I mix MySQL APIs in PHP?
What is the preferred method for getting the number of rows that are returned for a SELECT state when using PDO with prepared statements?
I am currently using rowCount() but the docs say I shouldn't be using that since "most databases" don't support it (It is actually working just fine for me, so I'm tempted to keep using it. I can't find any sources that list exactly which databases do not support it, but apparently mine is fine).
Instead they recommend I use fetchColumn() but that requires writing a completely separate SQL statement that includes the COUNT(*) in my sql statement.
This is what they propose (http://php.net/manual/en/pdostatement.rowcount.php#example-1038):
//SQL TO GET ROWS TO OUTPUT
$sql = 'SELECT *
FROM properties
WHERE lister_id = :lister_id
AND lister_type = "landlord"';
$result = $dbh->prepare($sql);
$result->bindParam(':lister_id', $_SESSION['loggedin_lister_id'], PDO::PARAM_INT);
$result->execute();
//SQL TO GET NUMBER OF RETURNED ROWS
$row_num_sql = 'SELECT COUNT(*)
FROM properties
WHERE lister_id = :lister_id
AND lister_type = "landlord"';
$row_num_result = $dbh->prepare($row_num_sql);
$row_num_result->bindParam(':lister_id', $_SESSION['loggedin_lister_id'], PDO::PARAM_INT);
$row_num_result->execute();
$num_rows = $row_num_result->fetchColumn();
if($num_rows > 0) {
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
echo $row['name'];
}
}
I find this method that requires me to write a separate and nearly identical sql statement to be redundant and a serious pain when using prepared statements. I can understand how this approach might be acceptable when using a short SQL statement with a basic query, but not in the case of a prepared statement.
1. Is there any other way I can use the fetchColumn() approach
without having to rewrite what is almost exactly the same code?
2. Where can I find an official list of which databases
rowCount() supports when using a SELECT statement? And since it is
working on the database I am currently using, can I assume it is safe
to use(assuming I am not updating my database anytime soon)?
If you don't want to use rowCount I'm think you should two query, or you can use fetchAll and count(fetchAll) for rowCount
the second way, Use SELECT *,COUNT(*) ...
PDO always returns field values as strings when using MySQL. Is PDO consistent when using another database like MSSQL?
If not, is there a flag which forces PDO to always return strings (for purpose of consistency)? or better still to return native types for all values?
From what I can tell, Drupal makes it possible to use different databases using PDO. It performs the necessary conversions to make SQL statements compatible with the varying syntaxes. But how does it deal with data types in query results?
If you want to make sure that you always get strings you can use bindColumn() and specify the data type for each column
$sql = 'SELECT id, name FROM test';
$stmt = $dbh->query($sql);
/* Bind by column number */
$stmt->bindColumn(1, $id, PDO::PARAM_STR); //or PDO::PARAM_INT
$stmt->bindColumn(2, $name, PDO::PARAM_STR);
while ($row = $stmt->fetch(PDO::FETCH_BOUND)) {
var_dump($id); var_dump($name);
}
In so far as I remember, this depends on the DB engine.
Some time ago, PDO would return a t or f strings for boolean fields in Postgres, and I vaguely recall that it was returning a true or false boolean the last time I used it.
You can normalize results into native types after checking getColumnMeta():
http://us3.php.net/manual/en/pdostatement.getcolumnmeta.php
Doing so comes with a few strings attached, though. The warnings in the php manual are one. The inconsistent values returned from an engine to the next are another:
List of PHP native_type's for PDO getColumnMeta()
I'm new to PHP. I have a select statement that returns 100 values for a particular record. I'd like to store these 100 values in an array. Is this the right command to store values that I get from a select statement into an array?
$result = mysql_query("select * from processed1 where record = ('$id') ");
$data = array();
while($row = mysql_fetch_array($result))
{
$data[] = $row; //IS THIS CORRECT?
}
Is there a way where I can avoid typing in the 100 attributes for my table? example : $row[1] ... $row[100]
If you are going to learn PHP in 2011, let's do it right.
First off, mysql_query or mysql_ anything code is deprecated. Don't use it anymore.
Don't worry - what I am suggesting works great with mysql databases, but it will also work great with any database:
PDO is what the PHP community continues to add features to, so I would use that.
PDO is also way more powerful, and makes it easier to switch databases later.
MYSQLi (the i stands for improved) replaces deprecated mysql_ based queries, but I would definitely go straight to using PDO.
You could also easily create an array
of objects later with one line change!
Secondly, Phil mentioned fetchAll(). This is the end goal. The other ways simply move thru it one row at a time. This uses a bulldozer instead of a shovel. Note: not the best way of selecting really large amounts of data, as it will use up memory. Otherwise, it is fine.
To get there, use prepared procedures to protect your code from SQL injection attacks.
<?php
/* Execute a prepared statement by binding PHP variables */
$calories = 150;
$colour = 'red';
$sth = $dbh->prepare('SELECT name, colour, calories
FROM fruit
WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories, PDO::PARAM_INT);
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12);
$sth->execute();
/* Fetch all of the rows into an array */
print("Fetch all of the remaining rows in the result set:\n");
$result = $sth->fetchAll();
print_r($result);
?>
Your code looks fine to me. But I would suggest to use mysql_fetch_assoc() instead of mysql_fetch_array(), so that keys are mapped to their values. Also, use mysql_real_escape_string() to prevent SQL injection.
$query = "Select * from processed1 where record = '".mysql_real_escape_string($id)."'";
$result = mysql_query($query);
$data = array();
while($row = mysql_fetch_assoc($result))
{
$data[] = $row;
}
If you're trying to store all the database rows into an array, yes, that code should do it. A few comments, though:
As curiou57 suggested, use mysql_fetch_assoc() to be able to refer to columns in an individual row by their names. (ex: foreach ($data as $row) { echo $row['columnname']; })
Make sure you run $id through mysql_real_escape_string() if you have to continue using the mysql extension. This prevents SQL injection attacks.
If you don't have to continue using the mysql extension, consider using PDO or mysqli.
Switch to mysql_fetch_row() if you want to reference each column by a numeric index (note, zero-based). Otherwise, that looks correct.
If you decide to switch to PDO, you can use the handy PDOStatement::fetchAll() method, using the PDO::FETCH_NUM fetch style to fetch all rows as numeric arrays into an array.
This is the correct way:
while($rows[] = mysqli_fetch_assoc($result));
array_pop($rows); // pop the last row off, which is an empty row
I have tried fetching MySQL query results using mysql_fetch_row() and mysql_result() and numeric values are being returned as strings.
Is there any way to fetch the data as its datatype stored in the table?
The application will be querying many different queries so I will be unable to cast the values as the intended datatype on a 1 by 1 basis.
I don't think getting data in their native datatypes (i.e. anything else that strings) can be done in PHP 5.2...
In PHP 5.3, it becomes possible, if I remember correctly, when you are using the new (new as in PHP >= 5.3) mysqlnd (MySQL Native Driver) driver.
After more digging through my bookmarks I found this article about mysqlnd : PDO_MYSQLND: The new features of PDO_MYSQL in PHP 5.3
It says this (quote) :
Advantages of using mysqlnd for PDO
mysqlnd returns native data types when
using Server-side Prepared Statements,
for example an INT column is returned
as an integer variable not as a
string. That means fewer data
conversions internally.
But this is PHP 5.3 only (provided your version of PHP 5.3 is compiled with mysqlnd (and not the old libmysql)), and seems to only be the case for prepared statements :-(
Which doesn't quite help, in your situation, I guess...
And here's another one, still about the new features of mysqlnd, which talks about this for not only prepared statements : PHP: New network traffic, CPU and memory savings with mysqlnd.
Not sure this has been merged into the official mysqlnd driver, though -- best way would be to try ; but it'll still be PHP >= 5.3 only, anyway...
Another solution would be to have, on the PHP-side, some kind of a mapping-system (like an ORM) to convert results coming from the DB to PHP datatypes...
And yes, this is bad if you want to use operators like === and !==, which are type-sensitive...
try this if using mysqli instead of PDO
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
I've implemented this the manual way. It's actually not too bad, just a few lines.
As suggested, call mysqli_fetch_fields() on the resource resulting from your query.
Then from a mapping of the PHP field type numbers to MySQL data types (see industrious work here http://www.php.net/manual/en/mysqli-result.fetch-field-direct.php) you can convert your values from the wide range of database types returned as strings by MySQLi, into the appropriate type in PHP.
How much of a slowdown it is I'm not sure tho.
In addition to Pascal MARTIN's answer, if you use MySQLi prepared statements you will get the data back using native types.
Try this:
<?php
$mysqli = new mysqli("example.com", "user", "password", "database");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT, label CHAR(1))");
$mysqli->query("INSERT INTO test(id, label) VALUES (1, 'a')");
$stmt = $mysqli->prepare("SELECT id, label FROM test WHERE id = 1");
$stmt->execute();
$res = $stmt->get_result();
$row = $res->fetch_assoc();
printf("id = %s (%s)\n", $row['id'], gettype($row['id']));
printf("label = %s (%s)\n", $row['label'], gettype($row['label']));
?>
The above example will output:
id = 1 (integer)
label = a (string)
You can get more info here:
https://dev.mysql.com/doc/apis-php/en/apis-php-mysqli.quickstart.prepared-statements.html
I wrote a function to circuvent this (for PDO):
/**
* Converts columns from strings to types according to
* PDOStatement::columnMeta
*
* #param PDOStatement $st
* #param array $assoc returned by PDOStatement::fetch with PDO::FETCH_ASSOC
* #return copy of $assoc with matching type fields
*/
function convertTypes(PDOStatement $statement, $assoc)
{
for ($i = 0; $columnMeta = $statement->getColumnMeta($i); $i++)
{
$type = $columnMeta['native_type'];
switch($type)
{
case 'DECIMAL':
case 'TINY':
case 'SHORT':
case 'LONG':
case 'LONGLONG':
case 'INT24':
$assoc[$columnMeta['name']] = (int) $assoc[$columnMeta['name']];
break;
case 'DATETIME':
case 'DATE':
case 'TIMESTAMP':
$assoc[$columnMeta['name']] = strtotime($assoc[$columnMeta['name']]);
break;
// default: keep as string
}
}
return $assoc;
}
Of course the type list are not complete and the conversion is oversimplified, but can be useful for start.