I have a function that retrieves all tags from a table:
function global_popular_tags() {
$this->db->select('tags.*, COUNT(tags.id) AS count');
$this->db->from('tags');
$this->db->join('tags_to_work', 'tags.id = tags_to_work.tag_id');
$this->db->group_by('tags.id');
$this->db->order_by('count', 'desc');
$query = $this->db->get()->result_array();
return $query;
}
I have another table called 'work'. The 'work' table has a 'draft' column with values of either 1 or 0. I want the COUNT(tags.id) to take into account whether the work with the specific tag is in draft mode (1) or not.
Say there are 10 pieces of work tagged with, for example, 'design'. The COUNT will be 10. But 2 of these pieces of work are in draft mode, so the COUNT should really be 8. How do I manage this?
Try changing:
$this->db->from('tags');
$this->db->join('tags_to_work', 'tags.id = tags_to_work.tag_id');
To:
$this->db->from('tags, work');
$this->db->join('tags_to_work', 'tags.id=tags_to_work.tag_id AND work.id=tags_to_work.work_id');
And Adding:
$this->db->where('work.drafts', 0);
You can use pure sql instead of using the active record class, I myself are working with CI for over 2 years and most of the time I am avoiding the active record class, cause straight sql is much easier to debug and write complex queries.
This is how i would use it.
$sql = "SELECT...your sql here";
$q = $this->db->query($sql);
...
//Do something with your query here
Related
In my Model, I wrote this function with MySQL raw query
function get_question_result($lr_id)
{
$raw_query = 'SELECT question_record.qr_id, LEFT(question.question, 50) as question,
question.correct_answer
FROM question_record
INNER JOIN question ON question.q_id = question_record.q_id
WHERE question_record.lr_id = '.$lr_id.' ';
$query = $this->db->query($raw_query);
$questionresult = $query->result_array();
return $questionresult;
}
It worked fine. It gave me the array I want. I continued my project.
Then suddenly I was curious to try it in CI Active Record Class.
function get_question_result($lr_id)
{
$this->db->select('question_record.qr_id, LEFT(question.question, 50) as question, question.correct_answer');
$this->db->from('question_record');
$this->db->join('question', 'question.q_id = question_record.q_id', 'inner');
$this->db->where('question_record.lr_id', $lr_id);
$result = $this->db->get()->result_array();
return $result;
}
It didn't work. It gave me this error
PHP Fatal error: Call to a member function result_array() on a non-object
Just out of curiosity, where did I do wrong?
Was it me writing it wrong or the result data structure with Active Record is just different?
'cause when I tried it again in Active Record without selecting this field
LEFT(question.question, 50) as question
It worked but it didn't give the field I want. Do you guys know why?
In your $this->db->select() call you need pass FALSE as second parameter so that active record will not try to add backticks ` for your columns in select statement
function get_question_result($lr_id)
{
$this->db->select('question_record.qr_id, LEFT(question.question, 50) as question, question.correct_answer',FALSE);
$this->db->from('question_record');
$this->db->join('question', 'question.q_id = question_record.q_id', 'inner');
$this->db->where('question_record.lr_id', $lr_id);
$result = $this->db->get()->result_array();
return $result;
}
According to docs
$this->db->select() accepts an optional second parameter. If you set
it to FALSE, CodeIgniter will not try to protect your field or table
names with backticks. This is useful if you need a compound select
statement.
$this->db->select();
I'm trying to better understand how CI works.
This is my first table, app_news:
id / name
My second is app_news_comments:
id / id_news / comment
The model I use in order to display news informations is:
public function get_news($where = array()) {
return $this->db->select('*')
->from('app_news')
->where($where)
->get()
->result();
}
The model I use in order to count comments for a news is:
public function count_comment($id_news) {
return (int) $this->db->where(array('id_news' => $id_news)
->count_all_results('app_news_comments');
}
The first solution I have is to print a foreach on my view and putting the count_comment function inside the loop in order to count how much comments I have however I won't respect the MVC pattern. How can I do so ?
The best way to get that information is using this query:
SELECT
app_news.id,
app_news.name,
COUNT(app_news_comments.id)
FROM app_news_comments
JOIN app_news ON app_news_comments.id_news = app_news.id
GROUP BY app_news_comments.id_news
So, you need to create a query using Active Record on Codeigniter or you could add the directly, because Active Record on Codeigniter have some restrictions.
However, you could use this way on Codeigniter to create the query:
$this->db->select('[YOUR FIELDS AND COUNT]', FALSE)
->from('app_news_comments') .... etc
and to add the query directly:
$this->db->query('[QUERY HERE]');
I hope this help you.
I'm building a search function and i'm pretty sure the proper way is to only get the # of results you want to display, in my case 20 per page. I'm wondering what is the best way for me to change that select('*') statement to return the total # of results select('count(*)'); and rerun the exact same query?
$this->db->select('*');
$this->db->from('MyTable');
$this->db->where('some complex conditions');
$this->db->join('a bunch of joins);
$this->db->limit('20','$page*20');
to
$this->db->select('count(*)');
/* reuse this part */
$this->db->from('MyTable');
$this->db->where('some complex conditions');
$this->db->join('a bunch of joins);
/* reuse this part */
run first query
$q1 = $this->db->get()->result_array();
run second query
$q2 = $this->db->get('q1 with different select')->result_array();
array_merge($q1,$q2);
Codeigniter actually has a pagination helper that is pretty useful:
https://ellislab.com/codeIgniter/user-guide/libraries/pagination.html
If you don't prefer to use it, you can pass in the current query number that you are at to the controller through the url.For example www.example.com/page/search/40. Where the query will then take that number to use for the limit.
You Can also do this way
// For required output
$this->db->select('');
$this->db->from();
$this->db->join();
$this->db->order_by();
$this->db->limit((int)$page['limit'],(int)$page['start']);
$list['list'] = $result->result();
// To count total number of rows
$this->db->select('');
$this->db->from();
$this->db->join();
$this->db->order_by();
$result_total = $this->db->get();
$list['list'] = $result->result();
$list['total'] = $result_total->num_rows();
return $list;
}
I am building an online tool for soccerclubs in php. Part of the system is a match module where you can make a video analysis, give grades to players, and more.
Everything is working fine, only problem being the performance of the initial pageload. The reason behind the problem is the database and the way im getting and presenting the data from the database.
My current database looks like this(I removed all unnecessary fields):
http://i.stack.imgur.com/VZnpC.png
When I'm done getting my data from my database I have an object like this:
$match->formations[]->positiongroups[]->positions[]->users[]->statgroups[]->stats[]
The way I'm getting the data takes way to much time( about 12 seconds ) and I'm probably doing it completely wrong. You can see the code below. I use laravel 4 as framework so most code isn't plain php but I think when you read the code you will understand what every line of code does. I do want to notice that an non-laravel solution is fine!
/*
* Get fullmatch info
* Returned value consists of
* $match->formation->positiongroups[]->positions[]->users[]->statgroups[]->stats[]
*/
public static function fullMatch($id){
//Get match of given id with formation and team
$match = Match::where('id', '=', $id)->with('formation', 'team.formation.positions', 'team.category')->first();
if($match->formation){
//Set all positiongroups in $match->formation
$match->formation->positiongroups = Positiongroup::all();
//Get possible positions
foreach(Formation::find($match->formation->id)->positions as $position){
$positions[] = $position->id;
}
//Loop through all positiongroups in $match->formation
foreach($match->formation->positiongroups as $positiongroup){
//Set all positions in positiongroups
$positiongroup->positions = Position::where('positiongroup_id', '=', $positiongroup->id)->whereIn('id', $positions)->get();
foreach($positiongroup->positions as $position){
$position->users = DB::table('formation_position_match_user')
->leftJoin('users', 'user_id', '=', 'users.id')
->where('formation_id', '=', $match->formation->id)
->where('position_id', '=', $position->id)
->where('match_id', '=', $match->id)
->get();
foreach($position->users as $user){
$user->statgroups = Statgroup::where('video', '=', 1)->with('Stats')->get();
$user->stats = DB::table('stat_statdate_user')
->leftJoin('statdates', 'statdate_id', '=', 'statdates.id')
->where('stat_statdate_user.user_id', '=', $user->id)
->groupBy('stat_statdate_user.stat_id')
->orderBy('stat_statdate_user.stat_id')
->get();
}
}
}
}
return $match;
}
If there is more information needed I'm happy to add it to the post.
I haven't seen the queries it produces, but I think you have too many nested foreach loops and you are sending too many queries to database. You should minimize number of queries. You can do it manually or use some library. For example NotORM
edit: Here is example of what you could easily do and improve the performance:
You should focus on getting more data at once, than doing it row by row. For example replace some = in WHERE conditions with IN ();
so instead of sending a lot of queries like
SELECT * FROM positions WHERE position_group_id = x;
SELECT * FROM positions WHERE position_group_id = y;
SELECT * FROM positions WHERE position_group_id = z;
you send only one SELECT to server:
SELECT * FROM positions WHERE position_group_id IN (x, y, z);
You will have to modify your code, but it won't be that difficult... I don't know how your where method works, and if it supports IN statement, but if it does, do something like this:
$position_group_ids = array();
foreach ($match->formation->positiongroups as $positiongroup) {
$position_group_ids[] = $positiongroup->id;
}
$all_positions = Position::where('positiongroup_id', 'IN', $position_group_ids);
I have a function which I use all over the place to pull users friends out of a database. However I recently had to delete a few users for causing problems on the forums, this has given me a few "Trying to get property of non-object" problems and I have traced it down to this function.
function isFriend($user_id, $friend_id){
$this->db->from('friends');
$this->db->where('user_id', $user_id);
$this->db->where('friend_id', $friend_id);
$this->db->where('removed', 0);
$query = $this->db->get();
$result = $query->result();
return count($result);
}
Does anyone know how I can adjust this function to ignore deleted users?
If all you're doing is counting the results you can try this instead:
$this->db->count_all_results();
Like this:
function isFriend($user_id, $friend_id)
{
$num = $this->db
->from('friends')
->where('user_id', $user_id)
->where('friend_id', $friend_id)
->where('removed', 0)
->from('TABLE_NAME')
->count_all_results();
return $num;
}
It should return 0 if there are no results, whereas $query in your current function (I believe) may not return an object you can call result() on (hence your error).
http://codeigniter.com/user_guide/database/active_record.html
$this->db->count_all_results();
Permits you to determine the number of rows in a particular Active
Record query. Queries will accept Active Record restrictors such as
where(), or_where(), like(), or_like(), etc. Example:
echo $this->db->count_all_results('my_table'); // Produces an integer, like 25
$this->db->like('title', 'match');
$this->db->from('my_table'); echo
$this->db->count_all_results(); // Produces an integer, like 17
There may be "better" ways, but without knowing the guts of your application it's hard to say.
why did you actualy remove them from database when you have the flag "removed" ?
Anyway, i think you should also remove the connections of those removed users, i don't see anything wrong with the function.
Trying to alter the function to work, it's just a hack and it's not good practice.
I think the function itself looks fine but it seem likely your errors are caused when the query returns 0 results.
if the removed col in the friends table or the users table?
Maybe you should perform a join to the users table.