I have this function which retrieves twwets from a certain user which are stored in a db. If I use ORDER BY ASC, like in the example, I get the right result, but if I use order by DESC the latest tweet is always omitted and missing in the array. Can't see why this is. All help much appreciated!
public static function getTweets($id, $order="created ASC") {
$dbh = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$stmt = $dbh->prepare("SELECT * from tweet
WHERE userid=:id
ORDER BY " . mysql_escape_string($order) . ""
);
$stmt->bindParam(':id', $id);
$stmt->execute();
$row = $stmt->fetch();
while ( $row = $stmt->fetch() ) {
$article = new Article( $row );
$list[] = $article;
}
return $list;
}
Comment this line,
//$row = $stmt->fetch();
while ( $row = $stmt->fetch() ) {
Related
I have a script that manage my tables and contains function to get list or to get certain data by id.
Right now one of my functions looks like this
//Returns a Series Object matching the given series id
public static function getById( $WHERE, $id ){
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "SELECT * FROM series $WHERE $id";
$st = $conn->prepare( $sql );
$st->execute();
$row = $st->fetch();
$conn = null;
if( $row ) return new Series( $row );
}
But I want it to be like this
//Returns a Series Object matching the given series id
public static function getById( $statement ){
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "SELECT * FROM series $statement";
$st = $conn->prepare( $sql );
$st->execute();
$row = $st->fetch();
$conn = null;
if( $row ) return new Series( $row );
}
So instead of having to do this
$series = Series::getById( ( string ) "WHERE id=", (int) $_POST['seriesId'] );
I can do this
$series = Series::getById( ( string ) "WHERE id=$_POST['seriesId']" );
The correct way of passing that value to your function would be like below:
$series = Series::getById("WHERE id=".$_POST['seriesId']);
I have a problem getting SELECT FOUND_ROWS() to return 0 when the result from MSQL query is empty.
I have the following function that calls getBasket();
function viewBasket(){
include('classes/Orders.php');
$BasketID = 10;
$numRows=100;
$data = Orders::getBasket( $numRows, $BasketID);
$results['basket'] = $data['results'];
$results['totalRows'] = $data['totalRows'];
require( "templates/Basket.php" );
};
getBasket() builds the required results using LEFT OUTER JOIN and places into an array which is then returned to viewBasket().
public static function getBasket( $numRows, $BasketID ) {
$order="Name ASC";
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$sql = "
SELECT SQL_CALC_FOUND_ROWS B.BasketID
, BP.ProductID
, BP.Quantity
, P.Name
, P.Price
, PT.NameType
FROM Basket B
LEFT
JOIN BasketProducts BP
ON B.BasketID = BP.BasketID
LEFT
JOIN Products P
ON BP.ProductID = P.ProductID
LEFT
JOIN ProductTypes PT
ON P.ProductTypeID = PT.ProductTypeID
WHERE B.BasketID = :BasketID
ORDER
BY $order
LIMIT :numRows;
";
$st = $conn->prepare( $sql );
$st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );
$st->bindValue( ":BasketID", $BasketID, PDO::PARAM_INT );
$st->execute();
$list = array();
while ( $row = $st->fetch() ) {
$basket = new Orders( $row );
$list[] = $basket;
}
// Now get the total number of articles that matched the criteria
$sql = "SELECT FOUND_ROWS() AS totalRows";
$totalRows = $conn->query( $sql )->fetch();
$conn = null;
return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );
}
My HTML then echos the totalRows value stored in $results by viewBasket();
<p>You have <?php echo $results['totalRows']?> item<?php echo ( $results['totalRows'] != 1 ) ? 's' : '' ?> in your Basket</p>
It works, but just wont send a 0 if the table is empty !
Thanks, Adam
I cannot reproduce the problem using php-5.6.3 and mysql-5.6 (default: myisam) under windows.
<?php
define('DB_DSN', 'mysql:host=localhost;dbname=test;charset=utf8');
define('DB_USERNAME', 'localonly');
define('DB_PASSWORD', 'localonly');
var_dump( getBasket(10, 1) );
function getBasket( $numRows, $BasketID ) {
$order="Name ASC";
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
setup($conn); // boilerplate: creating empty, temp tables
$sql = "
SELECT
SQL_CALC_FOUND_ROWS
Basket.BasketID, BasketProducts.ProductID, BasketProducts.Quantity,
Products.Name, Products.Price, ProductTypes.NameType
FROM
soBasket as Basket
LEFT OUTER JOIN
soBasketProducts as BasketProducts
ON
Basket.BasketID = BasketProducts.BasketID
LEFT OUTER JOIN
soProducts as Products
ON
BasketProducts.ProductID = Products.ProductID
LEFT OUTER JOIN
soProductTypes as ProductTypes
ON
Products.ProductTypeID = ProductTypes.ProductTypeID
WHERE
Basket.BasketID = :BasketID
ORDER BY
" . $order . " LIMIT :numRows
";
$st = $conn->prepare( $sql );
$st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );
$st->bindValue( ":BasketID", $BasketID, PDO::PARAM_INT );
$st->execute();
$list = array();
while ( $row = $st->fetch() ) {
$basket = new Orders( $row );
$list[] = $basket;
}
// Now get the total number of articles that matched the criteria
$sql = "SELECT FOUND_ROWS() AS totalRows";
$totalRows = $conn->query( $sql )->fetch();
$conn = null;
return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );
}
class Orders {
public $_data;
public function __Construct(array $data) {
$this->_data = $data;
}
}
function setup($pdo) {
$queries = array(
"
CREATE TEMPORARY TABLE soBasket (
BasketID int
)
",
"
CREATE TEMPORARY TABLE soBasketProducts (
ProductID int,
BasketID int,
Quantity int
)
",
"
CREATE TEMPORARY TABLE soProducts (
ProductID int,
ProductTypeID int,
Price DECIMAL(10,2),
Name varchar(64)
)
",
"
CREATE TEMPORARY TABLE soProductTypes (
ProductTypeID int ,
NameType varchar(64)
)
"
);
foreach( $queries as $q ) {
$pdo->exec($q);
}
}
prints
array(2) {
'results' =>
array(0) {
}
'totalRows' =>
int(0)
}
if($results['totalRows'] > 0){
echo $results['TotalRows'];
else{
echo '0';
}
an IF condition before echoing would do it.
Try to cast it:
return ( array ( "results" => $list, "totalRows" => (int)$totalRows[0] ) );
thanks to the input from #VolkerK and #Phate01 I have solved the issue.
I cleared the BasketID set in the basket table if the row returned from basketProducts is NULL. i.e. if I have removed the last row from products associated to that user, remove the cart session from Basket.
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$st = $conn->prepare ( "select BasketID FROM basketProducts WHERE BasketID = :basketID" );
$st->bindValue(":basketID", $basketID, PDO::PARAM_INT );
$st->execute();
$row = $st->fetch();
$conn = null;
/**
* If the row returned from BasketProducts DOES NOT include the customers $basketID
* remove the row.
**/
if($row == 0){
$conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
$st = $conn->prepare ( "DELETE FROM Basket WHERE BasketID = :basketID LIMIT 1" );
$st->bindValue(":basketID", $basketID, PDO::PARAM_INT );
$st->execute();
$row = $st->fetch();
$conn = null;
}else{
//do nothing
}
#VolkerK, I had a quick read of that link and its gone over my head. Will read up tonight, but would you mind explaining how this might help me?
here is the code before implementing the function,
try {
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5');
$stmt->execute(array(':published' => 'published'));
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$contents = $result['content'];
$title = $result['title'];
....
this works fine. Then i moved db connecting commands to separate php file(functions.php). and created this function,
function run_db($sqlcom,$exe){
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
$data_db = $stmt->fetch(PDO::FETCH_ASSOC) ;
return $data_db;
}
Then i changed first mentioned code like this,
try {
$data_db=run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
while ($result = $data_db) {
$contents = $result['content'];
$title = $result['title'];
Then all i got was one post repeating infinitely. Can anyone tell me how to correct this?
Change the function to this:
function run_db($sqlcom,$exe){
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt;
}
and the call to that function to:
try {
$stmt = run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$contents = $result['content'];
$title = $result['title'];
EDIT: Better solution is the one that jeroen advices - to return all the fetched objects at once:
function run_db($sqlcom,$exe){
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Then calling this way:
try {
$data = run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
foreach($data as $result) {
$contents = $result['content'];
$title = $result['title'];
EDIT 2: Anyway - wrapping such a logic into one function is not very good idea. now You are limited with executing of only SELECT queries and the resulting array containing always only record's associative array. What if You would like to (for any reason) retrieve the array of objects, or even only one single value? What if You would like to execute INSERT, UPDATE, DELETE queries???
If You for sure want to go this way, then I'd suppose creating a class with functions like this:
class MyPDO {
private $connection;
static $instance;
function __construct() {
$this->connection = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
static function getInstance() {
return self::$instance ? : self::$instance = new MyPDO;
}
// retrieves array of associative arrays
function getAssoc($sqlcom, $exe) {
$stmt = $this->connection->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// retrieves array of objects
function getObj($sqlcom, $exe) {
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchAll(PDO::FETCH_OBJ);
}
// retireves one single value, like for SELECT 1 FROM table WHERE column = true
function getOne($sqlcom, $exe) {
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt->fetchColumn();
}
// just executes the query, for INSERT, UPDATE, DELETE, CREATE ...
function exec($sqlcom, $exe){
$stmt = $conn->prepare($sqlcom);
return $stmt->execute($exe);
}
}
Then You can call it this way:
try {
$pdo = MyPDO::getInstance();
foreach($pdo->getAssoc('MySQL QUERY'), array($param, $param)) as $result) {
print_r($result);
}
} catch(\Exception $e) {
// ...
}
Just return the statement:
function run_db($sqlcom,$exe){
static $conn;
if ($conn == NULL)
{
$conn = new PDO('mysql:host=localhost;dbname=dbname', 'usr', 'pass');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
$stmt = $conn->prepare($sqlcom);
$stmt->execute($exe);
return $stmt;
}
try {
$stmt=run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$contents = $result['content'];
$title = $result['title'];
And you could also set the default fecth mode on the connection.
An alternative to the correct answers that return $stmt from the function, would be to fetch all rows in the function and use a foreach in your main code:
In function:
...
$data_db = $stmt->fetchAll(PDO::FETCH_ASSOC) ;
return $data_db;
Outside of function:
$data_db=run_db('SELECT * FROM posts WHERE status= :published ORDER BY id DESC LIMIT 5',array(':published' => 'published'));
foreach ($data_db as $result) {
$contents = $result['content'];
$title = $result['title'];
...
There are two essential problems with your code.
It connects every time it runs a query.
It returns data in only one format, while PDO can return results in dozens different formats.
Accepted answer makes it wrong, as it is just trying to reinvent PDO features, but very dirty way, with a lot of duplicated code and still failing to make it as good as with vanilla PDO.
As it said in xdazz's answer, you have to return the statement. And then use PDO's native fetch mode to get the result in desired format, using method chaining.
Also, you shouldn't add try to your code.
I am using SQLite for one of my application I’ve a condition that I first run a query and if it returns result then I retrieve its data but if the first query doesn’t return anything I want to run another query that ll just select any random row from the database and ll return the results.
I’ve devised following code its working fine if it matches the data in the first case but this is not working for the second case.
$sql_query = "SELECT (select count(*)) as count,* FROM item WHERE combo LIKE '%" . $ans_combo . "%' LIMIT 1;";
$sql_query_bu = "SELECT * FROM item ORDER BY RANDOM() LIMIT 1;";
ini_set('display_errors', true);
error_reporting(E_ALL);
try {
$dbh = new PDO("sqlite:src/appdb.s3db");
$dbh -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbh -> setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = $dbh -> prepare($sql_query);
$stmt -> execute();
foreach ($stmt as $row) {
if ($row['count'] != '1') {
echo $sql_query_bu . "<br/>";
$stmt = $dbh -> prepare($sql_query_bu);
$stmt -> execute();
foreach ($stmt as $row) {
echo $row['name'], " ", $row['name'], " ", $row['name'], "\n";
}
}
echo "Count: " . $row['count'];
echo $row['name'], " ", $row['name'], " ", $row['name'], "\n";
}
} catch(Exception $ex) {
var_dump($ex);
}
unset($dbh);
unset($stmt);
Kindly guide me through this.
Thank you.
If there is no record that matches the WHERE clause the first call to fetch() will return FALSE. In that case you can simply send the ORDER BY RANDOM()* query and fetch the first record.
self-contained example:
<?php
$pdo = new PDO('sqlite::memory:');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
setup($pdo);
$stmt = $pdo->prepare('SELECT * FROM soFoo WHERE combo=? LIMIT 1');
$stmt->execute( array('comboF') ) ;
$row = $stmt->fetch();
$stmt = null;
if ( !$row ) {
$row = $pdo->query('SELECT * FROM soFoo ORDER BY RANDOM() LIMIT 1')->fetch();
}
var_dump($row);
function setup($pdo) {
$pdo->exec('
CREATE TABLE soFoo (
combo TEXT,
x TEXT
)
');
$stmt = $pdo->prepare('INSERT INTO soFoo (combo,x) VALUES (?,?)');
$stmt->execute( array('comboA','A') );
$stmt->execute( array('comboB','B') );
$stmt->execute( array('comboC','C') );
$stmt->execute( array('comboD','D') );
}
(*) ORDER BY RANDOM() is e.g. in MySQL rather costly. I doubt that SQLite has a special routine for this case. Better search for a good alternative for ORDER BY RANDOM()
This has annoyed me for a while now. I am trying this query in phpmyadmin.
select `id` from `users` where `fb_id` = 507292797 limit 1
This returns the value 13, so why doesn't this work:
$sql = "select `id` from `users` " .
"where `fb_id` = :fb_id " .
"limit 1";
try
{
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':fb_id', $fb_id2, PDO::PARAM_INT);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
$result = $stmt->execute();
$stmt->closeCursor();
}
catch (Exception $e)
{
die ($e->getMessage() );
}
echo "id: " . $fb_id2 . " var_dump: " . var_dump($user);
exit();
This returns:
id: 507292797 var_dump: bool(false)
When var_dump should return $user['id'] = 13
Can somebody see what I am doing wrong here?
ps. here is my db connection function if that matter
$dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME;
$driver_options = array( PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8' );
try
{
$this->db = new PDO($dsn, DB_USER, DB_PASS, $driver_options);
You are doing things in this order :
Preparing the statement
Binding the variables
Trying to fetch data from the statement
Executing the statement
The two last steps should be in the inverse order : you must execute the statement before you can fetch data (that's obtained by executing it).
Basically, instead of using this :
// fetch, then execute ???
$user = $stmt->fetch(PDO::FETCH_ASSOC);
$result = $stmt->execute();
You should use that :
// Execute, **then** fetch
$stmt->execute();
$user = $stmt->fetch(PDO::FETCH_ASSOC);
Looks like you are fetching before executing?