how to "keep" codeigniter activerecord status - php

In my article CURD list, I need to get articles from database using many conditions, after get number of eligible articles(no limit), I need to get first 10 eligible articles (limit 10). So I want to keep the activerecord status, if it's possible, I don't need to write those 'where' again. Here are my code:
//select num
$this->db->select('count(*) as num')
//conditions
$this->db->where/or_where/having/order_by//many conditions...
//get num
$num = $this->db->get('articles')->first_row()->num;
//get articles
$this->db->limit(10);
$articles = $this->db->get('articles')->result();
When I finished my first query, the active record status is empty, so the second query is wrong. Is there any way to keep that?

I know this is old, but I was also looking for a way to do this, eventually found the built in solution:
// Start of the query you want to re-use
$this->db->start_cache();
//select num
$this->db->select('count(*) as num')
//conditions
$this->db->where/or_where/having/order_by//many conditions...
// End of the query you want to re-use
$this->db->stop_cache();
//get num
$num = $this->db->get('articles')->first_row()->num;
//get articles
$this->db->limit(10);
$articles = $this->db->get('articles')->result();
// Clear the saved query
$this->db->flush_cache();

I believe there is no reason why the approach you are taking shouldn't work. For instance taking your code snippet, tidying up and applying some conditions to it:
//select num
$this->db->select('count(*) as num');
//conditions
$this->db->where(array('title' => 'Hello world'));
//get num
$num = $this->db->get('articles')->first_row()->num;
//get articles
$this->db->limit(10);
$articles = $this->db->get('articles')->result();
echo "!".$num."!<br />";
print_r($articles);
exit();
Using this within my test application I gather the $num result and then a full recordset within $articles.

You could just use a simple if clause
function get_data($type) {
//select num
$this->db->select('count(*) as num')
//conditions
$this->db->where/or_where/having/order_by//many conditions...
//get num
if($type == 'count')
return $this->db->get('articles')->first_row()->num;
//get articles
if($type == 'articles') {
$this->db->limit(10);
return $this->db->get('articles')->result();
}
}
Although I am not sure if there is anything specific for codeigniter that can simplify this, this should work.

Related

CodeIgniter: How to get the number of records before get all results?

I need to get the number of records for a query before apply a limit. I tried with the following code:
$db = $this->load->database();
$this->db->select($this->select_column)
->from($this->table);
echo $this->db->count_all_results();
But count_all_results don't return any number. If I excecute $this->db->get(), I obtained a result sets, but first I need to apply a limit.
What can be happenning with $this->db->count_all_results()?
Is there another solution for get the count of rows returned based on the previews query?
I'm using Codeigniter 3 with MySQL.
Try doing the the following first to get the count:
$this->db->select('count(*) as ct');
$count = $this->db->get($this->table)->result()[0]->ct;
Now your variable $count has the count you need to apply the limit, so you can
$this->db->.... // Your code
$this->load->database(); // Database is lodaed
$query = $this->db->get('table_name');
return $query->num_rows();
// This will return count of total rows
//After that you can return the result
return $query->result();

Get count query results via getSingleScalarResult() and groupBy() - exception

I want get results of my query (with limit 10) + count possible results.
I know there is similar questions and answers.
for example here
but if i trying get count possible rows (via getSingleScalarResult()) i will get excepton: The query returned multiple rows. Change the query or use a different result function like getScalarResult().
$query = $repository
->createQueryBuilder('t')
->select('COUNT(t.katId)', 't.hotel', 't.title', 't.desc', 'picture', 'MIN(t.price) AS price');
$query->where('t.visible = (:visible)')->setParameter('visible', 1);
// + some wheres, where in, more than....
$query->groupBy('t.hotel');
$query->setMaxResults(10);
echo $query->getQuery()->getSingleScalarResult();
exit();
I just need one integer whitch represent all results from my query.
How can i get this count number? Ideal in one shot to db.
EDIT:
if i remove $query->groupBy('t.hotel'); and in select keep only ->select('count(t.katId)'); then it work. But i need groupBy because it makes real count of results.
SOLUTION
I divided it on two queries so - to get results i rolled back changes to state before trying any count information, and make clone this query (before set setMaxResults and groupBy), change select (keep all wheres) and get count information.
I will be grateful if someone offers better solution
Get results:
removed COUNT() from select
asking for results changed to 'normal' ->getArrayResults
Get count:
$q = clone $query;
$q->select('count(distinct t.hotel) as count');
$r = $q->getQuery()->getArrayResult();
echo $r[0]['count'];
exit();
If you need keep the groupBy:
$query = $repository->createQueryBuilder('t')
$query->select('COUNT(t.katId)', 't.hotel', 't.title', 't.desc', 'picture', 'MIN(t.price) AS price');
$query->from(ENTITY STRING, 't', 't.hotel'); //here defined your array result key
$query->where('t.visible = (:visible)')->setParameter('visible', 1);
$query->groupBy('t.hotel');
$query->setMaxResults(10);
echo $query->getQuery()->getScalarResult();
exit();
Edit : New edit works ?
You are only interested in COUNT(t.katId), so you should drop other returned fields 't.hotel', 't.title', etc.
The result will then contain a single return value (single scalar result), so $query->setMaxResults(10) is not needed.

Check if multiple rows exist in MySQL using PHP

I am currently busy on a textbased RPG game, but I am stuck at one part right now.
In order to start a mission, the player does need some items, these are stored in a string: item:1x3-item:5x1 - (basicly item:IDxamount).I have already made a function that explodes the string into variables, but now the script needs to check if the player does have all the items listed.
I've tried to solve the issue with a foreach, but that returns positive or negative for every item, and I only need to know if the player has all items at once.
(don't mind the unsafe query)
$parseAmount is an array, containing all item ID's.
$uid is an variable containing userID
// check if player has all items
foreach($parseAmount as $itemID)
{
$check_query = mysql_query("SELECT * FROM `player_items` WHERE `player`='$uid' AND `item`=='$itemID' AND `value`>='$parseAmount[1]'");
if(mysql_num_rows($check_query)>=1)
{return true;}
else
{return false;}
}
If you want me to post the whole function, please let me know.
If I understood your question correctly you need something like:
foreach($parseAmount as $itemID) {
$sql = "SELECT COUNT(*) AS count
FROM player_items
WHERE player = '".mysql_real_escape_string($uid)."'
AND item = '".mysql_real_escape_string($itemID)."'
AND value >= ".intval($parseAmount[1]);
$row = mysql_fetch_array(mysql_query($sql));
if ($row['count'] == 0) {
return false;
}
}
return true;
You must not early return true. You know the result is true only after checking all the items. My code could be improved by selecting all the items at once, but it's up to you to build this.
Keep in mind my comment about the deprecation of the MySQL extension, using MySQLi and Prepared Statements it will look something like this (note that I never worked with MySQLi before and built it with help of the manual):
foreach($parseAmount as $itemID) {
$sql = "SELECT COUNT(*) AS count
FROM player_items
WHERE player = ?
AND item = ?
AND value >= ?"
$stmt = $mysqli->prepare($sql);
$stmt->bind_param("ssi", $uid, $itemID, $parseAmount[1]);
$stmt->execute();
$row = $stmt->get_result()->fetch_array();
if ($row['count'] == 0) {
return false;
}
}
return true;

Count rows before adding a further limit statement CodeIgniter?

I have ran into a problem...
I have a bunch of where statments like so...
$this->db->where('Pool', "1");
$this->db->where('Bedrooms >=', "3");
Then a limit statement
$this->db->limit($limit, $offset);
And finally my get statement
$query = $this->db->get('table-name');
My problem is I need to count the results before my limit statement, to get the total rows without the limit.. So I tried this..
$this->db->where('Pool', "1");
$this->db->where('Bedrooms >=', "3");
$num_rows = $this->db->count_all_results();
$this->db->limit($limit, $offset);
$query = $this->db->get('table-name');
This counts my rows with the where statements fine.. However, the get statement now gets records without the previous where statements working.
It's not visible, but there is a large amount of code handling more where statements, and grabbing things in urls, So I'd prefer not to perform the retrieval of data twice in order to fix this...
Cheers!
I know this is an old question, but I just ran into this problem and came up with a different solution.
The idea is to take a copy of the db class before the limit and offset.
$this->db->where('Pool', "1");
$this->db->where('Bedrooms >=', "3");
//here we use the clone command to create a shallow copy of the object
$tempdb = clone $this->db;
//now we run the count method on this copy
$num_rows = $tempdb->from('table-name')->count_all_results();
$this->db->limit($limit, $offset);
$query = $this->db->get('table-name');
I know that's an old question but I found a pretty simple solution.
//do your select, from and where
$this->db->select('your selects');
$this->db->from('your table');
$this->db->where('your where');
//get the filtered rows count
//the trick is the first empty parameter and second false parameter
$filtered_count = $this->db->count_all_results('', false);
//limit your results and get the rows
$this->db->limit($length, $start);
$results = $this->db->get()->result_array();
Hope it helps someone
$get_data = $this->your_model->get_data();
$data = $get_data['data'];
$count = $get_data['count'];
Model
function get_data($limit = 10, $offset= 0)
{
$table = 'table-name';
$where = array('Pool' => 1, 'Beedrooms >=' 3);
$return['data'] = $this->db->from($table)->where($where)->limit($limit, $offset)->get();
$return['count'] = $this->db->from($table)->where($where)->count_all_results();
return $return;
}
$this->db->select('*');
$this->db->from('users');
$this->db->where('active',$status);
//open1 here we copy $this->db in to tempdb and apply
//count_all_results() function on to this tempdb
$tempdb = clone $this->db;
$num_results= $tempdb->count_all_results();
// now applying limit and will get actual result
$this->db->limit(10);
$this->db->get();
$query = $this->db->last_query();
$res = $this->db->query($query);
$data_array = array('num_results' => $num_results, 'results' => $res->result() );
return $data_array;
It is quite evident that you would need to use two different queries. It would be optimum to do this as quickly as possible using a single query, but since you need to get all the records before the second query, we need to use two queries.
However, you can optimize the first query based on the engine you use with MySQL. If you use InnoDB then you should use SELECT COUNT(*) FROM <table-name> cause the total row size is cached in InnoDB.
I believe count_all_rows uses count(*) for performance and you should be sorted using this direcctly.
With MyISAM you can use COUNT(<column-name>).
So, you have a count function in your model class which returns the count for your table and then you can call the function to insert/update/get data from your database.
You can use SQL_CALC_FOUND_ROWS of mysql
SELECT SQL_CALC_FOUND_ROWS * FROM table1
WHERE
cond1, cond2, ..., condN
LIMIT 10
SELECT FOUND_ROWS();
This is using mysql, you may need to check how to use it codeignitor way.
Reference:
https://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_found-rows
I know this question is old but I had the same issue and got a simpler solution than the displayed here. No need to build the query twice and no need to clone the db class. Just count the result without resting the query builder after you add the where part and then you add the limit and execute your query.
$this->db->where('Pool', 1);
$this->db->where('Beedrooms >=' 3);
$count = $this->db->count_all_results('table-name', false); // No reset query builder
$this->db->limit($limit, $offset)
$result = $this->db->get();
You are going to have two variables:
$count with the number of results and $result with the result.

Codeigniter return result and row

In the Model class I use return $query->row(); to return single rows and return $query->result(); when returning multiple rows.
On a single page I have to return single rows and multiple rows from 2 separate tables.
Table users contains general information like the user name, full name, and email address.
Table user_links contains links submitted by the respective user and has multiple rows for each user.
My query
$this->db->select('*');
$this->db->from('users');
$this->db->join('user_links', "user_links.user_id = users.user_id");
$this->db->where('users.user_id', $user_id);
$this->db->where('user_links.user_id', $user_id);
$query = $this->db->get();
return $query->row();
In my controller I load the query in my view by
$data['row'] = $this->User_model->user_read($user_id);,
$user_id being the 3rd URL segment containing the unique user id.
Finally, in my view I retrieve rows by echo $row->first_name;
This works for single rows but how can I create a foreach loop for user links? The goal is to avoid loops for single rows and use them just for retrieving multiple rows.
This is psuedo code but you can probobly do something like this
$this->db->select('*');
$this->db->from('users');
$this->db->join('user_links', "user_links.user_id = users.user_id");
$this->db->where('users.user_id', $user_id);
$this->db->where('user_links.user_id', $user_id);
$query = $this->db->get();
if ($query->num_rows() == 1)
{
return $query->row();
}
elseif ($query->num_rows() > 1)
{
return $query->result_array(); //This returns an array of results which you can whatever you need with it
}
else
{
//Add some logic to handle if there are zero results
}
If I understand your question correctly, you want to get both the user data as well as user_links data with a single query while avoiding iterating through it to get the user's data. While this may be possible using result_array, I would advise against it since you will get 0 results when there are no entries in user_links for that particular user.
My suggestion is that you use two queries, one to get the user from the user table, another to get user's links from user_links table. This will also help you avoid joins.
Hard to tell what you want.
You want a function that checks if you're passing a row() or a result() and treat them accordingly.
In my opinion your code would be easier to read (and maintain) if you just passed everything as a result(). And do check if the set is empty to show a nice message to the user.
Sounds like you're looking for some of the other features already provided by CI's Active Record: http://codeigniter.com/user_guide/database/results.html
For what you are doing it sounds like using the built in function result_array would work. You use it like so:
TAKEN FROM LINK ABOVE
$query = $this->db->query("YOUR QUERY");
foreach ($query->result_array() as $row)
{
echo $row['title'];
echo $row['name'];
echo $row['body'];
}
You can just replace this line:
$this->db->join('user_links', "user_links.user_id = users.user_id");
With this one:
$this->db->join('user_links', "user_links.user_id = users.user_id", 'left outer');
Join in codeigniter uses INNER JOIN by default but in some cases if there is no data in user_links it returns nothing so u can use LEFT JOIN in your frame work CI it used like i mentioned above.

Categories