I'm quite annoyed with CI's behavior lately, may be because i'm little ignorant towards small stuff, now to the question :D. i'm making an application where i'm trying to get one single row using active records, now as a good programmer(i think) i try this
when i select such as login
if($query->num_rows() == 1)
{
// do something
}
// now when i make an update, that also a single row i tend to use this command
if($query->affected_rows() == 1)
{
// perform some action
}
// now i use this code when i've to get all entries of one single user
if($query->num_rows() > 0)
{
// show them
}
now many time i get error like "Call to member function num_rows() on non object"
can anyone please explain what to use, when to use and how to use, so that code igniter never gets made a me
1.num_rows()
num_rows() are result helper functions, they are used against a query resultobject, note that we don't use it like $this->db->num_rows(), instead we use it like:
$query = $this-query('query');
OR
$query = $this->db->get('tableName');
if($query->num_rows()>0){ ....}
Now lets see affected_rowS().
2. affected_rows()
affected_rows is a query helper function, they are used like $this->db->affected_rows(). Note that $this->db->affected_rows() yields valid result only after a valid db write operation. i.e insert, update and delete. The database class has a small hack that allows it to return the correct number of affected rows after a delete operation because MySQL "DELETE FROM TABLE" returns 0 affected rows.
3.$query->result()
This function returns the query result as an array of objects, or an empty array on failure.
i.e if you have more than one result you have to loop the result object like :
foreach ($query->result() as $row){....}
4.$query->row()
This function returns a single result row as an object. If your query has more than one row, it returns only the first row.
I hope my explanation is readable enough.. Although you could find all of these in CI docs with relevant examples.
Related
I have quite an issue I can not seem to solve. I am trying to get a row count from a select statement.
I should start by saying I have tried most all methods resulting from google searches on this issue.
I am using the result set so I would prefer not to make a second query.
The query uses a prepared select statement which seems to be a main issue if I understand it correctly.
I decided to try a simple approach using PHP's native count() function. Which lead me here because I finally reached the end of the rope on this.
On to the details...within a class of mine, I make the query like this.
// Create database connection
$database = DatabaseFactory::getFactory()->getConnection();
// Set and execute database query
$sql = "SELECT * FROM `service_orders` WHERE `agency_id` = :agency_id $filter ORDER BY $sort $order $per_page";
$query = $database->prepare($sql);
$query->execute($query_array);
// If results
if ($query->rowCount() > 0) {
$results = $query->fetchAll();
self::$order_count = "Count: " . count($results);
return $results;
}
// Default, return false
return false;
Findings
If I perform count($results) like I did above, I get the total rows in the database (Let's say 50).
If I print_r($results), it shows the array with the proper number of entries (Let's say 10) that of course differs from the total rows in the database.
How can these two differ? It's as if the count($results) is misreading the result array.
More Findings
Within my actual php page, I call the class to retrieve the data like this.
$results = OrderModel::getServiceOrders();
echo count($results);
Strangely enough, if I then perform count($results) it gives me the correct reading of the result array (which in my example here would be 10).
I am perplexed by this as the count function is being performed on the exact same array. The only difference is one is called on the array within the class, and the other is called on the array returned from the class.
Does anyone have any ideas on how to solve this or why there is the discrepancy when using count() in this instance?
Thank you all in advance!
James
Additional Info
This is another mind numbing scenario. If I return the count along with the actual results, I can access it on the page with the correct value (10 rows). Yet, if I set it into a session variable, and access it that way, the count is the whole data set (50 rows). How is it even possible these two values are not the same?!
$results = $query->fetchAll();
Session::set("order_count", $total[0]); // Yields 50 (incorrect)
return [
"results"=> $results,
"count"=> $total[0], // Yields 10 (correct)
];
Assume I have this piece of code:
foreach($creds as $cred){
$prev_fut = $pdo->query("SELECT importo FROM incassi_prev WHERE
data_prev='$data_fut' AND incasso=0 AND
id_cre='{$cred['id_cre']}'")->fetch();
if(count($prev_fut)>0){
//I have found a result
}else{
//I have found nothing
}
}
NOTE: It is an internal query for my application with no data posted by user so I don't worry about SQL injections.
I use to check if count($prev_fut)>0 to see if the query is returning data (if I find any row in the db with these criterias).
My question is:
is this check enough to verify that the query has at least a result? Is it better to perform any other check?
The question is mostly coming from my thoughts about this being in a for loop and is related to the option of emptying/unset the $prev_fut array before starting a new iteration of for loop.
fetchColumn returns a single value of the next row in the result set. count counts the length of an array. Since fetchColumn can't return an array (for most database implementations), using count on it is wrong. You want to test whether $prev_fut is false or not. false would indicate that no result could be fetched, while anything else means a result was fetched:
if ($prev_fut !== false) ..
Having said that, you should really use a COUNT() in the database and check that value:
$result = $pdo->query('SELECT COUNT(*) FROM ...')->fetchColumn();
if ($result > 0) ..
It's much more efficient to have the database count and summarise the result than fetching an entire result set into PHP just for this simple check.
When I execute a PDO statement, internally a result set is stored, and I can use ->fetch() to get a row from the result.
If I wanted to convert the entire result to an array, I could do ->fetchAll().
With Laravel, in the Query Builder docs, I only see a way to get an array result from executing the query.
// example query, ~30,000 rows
$scores = DB::table("highscores")
->select("player_id", "score")
->orderBy("score", "desc")
->get();
var_dump($scores);
// array of 30,000 items...
// unbelievable ...
Is there any way to get a result set from Query Builder like PDO would return? Or am I forced to wait for Query Builder to build an entire array before it returns a value ?
Perhaps some sort of ->lazyGet(), or ->getCursor() ?
If this is the case, I can't help but see Query Builder is an extremely short-sighted tool. Imagine a query that selects 30,000 rows. With PDO I can step through row by row, one ->fetch() at a time, and handle the data with very little additional memory consumption.
Laravel Query Builder on the other hand? "Memory management, huh? It's fine, just load 30,000 rows into one big array!"
PS yes, I know I can use ->skip() and ->take() to offset and limit the result set. In most cases, this would work fine, as presenting a user with 30,000 rows is not even usable. If I want to generate large reports, I can see PHP running out of memory easily.
After #deczo pointed out an undocumented function ->chunk(), I dug around in the source code a bit. What I found is that ->chunk() is a convenience wrapper around multiplying my query into several queries queries but automatically populating the ->step($m)->take($n) parameters. If I wanted to build my own iterator, using ->chunk with my data set, I'd end up with 30,000 queries on my DB instead of 1.
This doesn't really help, too, because ->chunk() takes a callback which forces me to couple my looping logic at the time I'm building the query. Even if the function was defined somewhere else, the query is going to happen in the controller, which should have little interest in the intricacies of my View or Presenter.
Digging a little further, I found that all Query Builder queries inevitably pass through \Illuminate\Database\Connection#run.
// https://github.com/laravel/framework/blob/3d1b38557afe0d09326d0b5a9ff6b5705bc67d29/src/Illuminate/Database/Connection.php#L262-L284
/**
* Run a select statement against the database.
*
* #param string $query
* #param array $bindings
* #return array
*/
public function select($query, $bindings = array())
{
return $this->run($query, $bindings, function($me, $query, $bindings)
{
if ($me->pretending()) return array();
// For select statements, we'll simply execute the query and return an array
// of the database result set. Each element in the array will be a single
// row from the database table, and will either be an array or objects.
$statement = $me->getReadPdo()->prepare($query);
$statement->execute($me->prepareBindings($bindings));
return $statement->fetchAll($me->getFetchMode());
});
}
See that nasty $statement->fetchAll near the bottom ?
That means arrays for everyone, always and forever; your wishes and dreams abstracted away into an unusable tool Laravel Query Builder.
I can't express the valley of my depression right now.
One thing I will say though is that the Laravel source code was at least organized and formatted nicely. Now let's get some good code in there!
Use chunk:
DB::table('highscores')
->select(...)
->orderBy(...)
->chunk($rowsNumber, function ($portion) {
foreach ($portion as $row) { // do whatever you like }
});
Obviously returned result will be just the same as calling get, so:
$portion; // array of stdObjects
// and for Eloquent models:
Model::chunk(100, function ($portion) {
$portion; // Collection of Models
});
Here is a way to use the laravel query builder for making the query, but to then use the underlying pdo fetch to loop over the record set which I believe will solve your problem - running one query and looping the record set so you don't run out of memory on 30k records.
This approach will use all the config stuff you setup in laravel so you don't have to config pdo separately.
You could also abstract out a method to make this easy to use that takes in the query builder object, and returns the record set (executed pdo statement), which you would then while loop over as below.
$qb = DB::table("highscores")
->select("player_id", "score")
->orderBy("score", "desc");
$connection = $qb->getConnection();
$pdo = $connection->getPdo();
$query = $qb->toSql();
$bindings = $qb->getBindings();
$statement = $pdo->prepare($query);
$statement->execute($bindings);
while ($row = $statement->fetch($connection->getFetchMode()))
{
// do stuff with $row
}
In the MySQL Reference Manual, there's distinction between data definition statements and data manipulation statements.
Now I want to know if a query inserts a database record, updates one, deletes one or modifies the table structure and so on, or, more precisely, the exact number of affected rows, but only if it is applicable.
For example, the statement
SELECT *
FROM SomeTable
WHERE id=1 OR id=2
returns a number of affected rows (in this case 2), but with the SELECT statement, there's nothing modified in the database, so that number would be 0.
How to get the type of query?
I was looking for the same answer and stumbled across this article. It was last updated in August. In it, there is a section: "Determining the Type of a Statement" You basically can make the following assumptions: (copied from the article)
If columnCount() is zero, the statement did not produce a result set. Instead, it modified rows and you can invoke rowCount() to determine the number of affected rows.
If columnCount() is greater than zero, the statement produced a result set and you can fetch the rows. To determine how many rows there are, count them as you fetch them.
I'll save you the trouble and just paste the code sample here
$sth = $dbh->prepare ($stmt);
$sth->execute ();
if ($sth->columnCount () == 0)
{
# there is no result set, so the statement modifies rows
printf ("Number of rows affected: %d\n", $sth->rowCount ());
}
else
{
# there is a result set
printf ("Number of columns in result set: %d\n", $sth->columnCount ());
$count = 0;
while ($row = $sth->fetch (PDO::FETCH_NUM))
{
# display column values separated by commas
print (join (", ", $row) . "\n");
$count++;
}
}
I have been thinking of the same issue, and come to conclusion that I don't need no automation in this matter.
The only use for such an auto-detect is some magic function which will return number of affected rows. But such a magic, although adding a little sugar to the syntax, always makes code support a nightmare:
When you're calling a function, and it can return values of different types depends on the context, you cannot tell which one is returned at every particular moment. So, it makes debugging harder.
So, for sake of readability, just call appropriate function to get the result you need at the moment - affectedRows or numRows. It won't make your code bloated, but make it a lot readable.
I'm using this:
substr($statement->queryString, 0, strpos($statement->queryString, ' '));
where $statement is a PDOStatement object, a few things to note here are that you should verify before using this that $statement is a PDOStatement object, also we should probably take the strpos out of the substr statement in case strpos returns false, which would probably cause an error, finally, this only works with one word statement types, like SELECT, INSERT, etc and not multi-word statement types like ALTER TABLE
$RSGetID = $this->MyDBObject->Prepare("SELECT FinalID FROM clothes
WHERE ClothID=:|1 AND PriceID = :|2 LIMIT 1");
$RSGetID->Execute(2, 199);
$ClothIDRow = $RSGetID->FetchRow();
return $ClothIDRow->FinalID;
This last line gives an error, because there are no rows in the table, so it says:
"the query did not return any records"
How do I put a condition, that if the table is empty then return 0 , else return the fetched FinalID from the database table?
You're using some custom DB layer (MyDBObject?) rather than straight-up PDO - it's impossible for us to know how this behaves. There's probably a method along the lines of ->RowCount() or ->NumRows() you can call to see if you got anything back after the ->Execute() - but this is just guessing, since I can't see the DB object you're using.