I have two tables books and authors. Using CodeIgniter I would like users to be able to Filter results - for example, show results where author_id = 'x' and book_lang = 'y' and publication_year = '2000'. Filter criteria values come from user via drop-downs.
What's the best way to generate the query using codeigniter helper and binding etc?
For example, the query below will give me everything with author_id= 1. what if filters are a mix, for example; author_id = 1; language = 'all' (don’t put where clause on language) and publication year = 'all' also don’t put where clause.. Do I manually need to check for values and code or is there a codigniter helper method that allows filter to be removed from where clause if dropdown value is 'show all'?
$sql = "select * from AUTHORs a , BOOKS b where
a.AUTH_ID = b.BOOK_AUTH_ID
and b.BOOK_AUTH_ID = ?
and b.BOOK_LANGUAGE = ?
and b.PUB_YEAR = ? ";
$query = $this->db->query($sql, array ($author_id, $book_lang, $pub_year));
You should use Codeigniter's Active Record class to construct your query:
$this->db->select('*');
$this->db->from('AUTHORs a , BOOKS b');
$this->db->where('a.AUTH_ID', 'b.BOOK_AUTH_ID');
if ($author_id != 'all') $this->db->where('b.BOOK_AUTH_ID', $author_id);
if ($book_lang != 'all') $this->db->where('b.BOOK_LANGUAGE', $book_lang);
if ($pub_year != 'all') $this->db->where('b.PUB_YEAR', $pub_year);
$query = $this->db->get();
To read more about Codeigniter's Active Record class, visit the Docs:
http://codeigniter.com/user_guide/database/active_record.html
Related
I'm in a situation where I'm doing a MySQL query with Codeigniter and where I have a lot of fields value request which are ALL the same.
Example:
$this->db->query('SELECT * FROM abc WHERE user_id = ? AND msg_from = ? AND msg_to != ?', [$id, $id, $id]);
This has just 3 question marks but the query I'm working on is HUGE and has 19 question marks WHICH ARE ALL THE SAME variable.
So I was trying to figure out how to tell Codeigniter all question marks are pointing to the same variable without having to fill an array with 19 times the same variable.
I thought of a for-loop but I wanted to know if a shortcut exist.
you should be able to do this with Codeigniters Query Builder pretty easily
Something like that should work:
$this->db
->select('*')
->from('abc');
$arrFields = array('users_id', 'msg_from', 'msg_to');
foreach($arrFields AS $val)
{
$this->db->where($val, $id);
}
$query = $this->db->get();
I am using the CodeIgniter database class to generate results and then use the pagination class to navigation through them. I have a model that retrieves member results from the table. I would like to calculate the total number of rows from the query so I can pass this to the pagination class. The count_all db helper function won't suffice because that doesn't take in account any "where" or "join" clauses that I include.
If this is my query:
$this->db->select('m.user_id AS id, m.email_address, m.display_name, m.status, UNIX_TIMESTAMP(m.join_date) AS join_date,
l.listing_id, COUNT(l.member_id) AS total_listings,
g.group_id AS group_id, g.title AS group_title')
->from('users AS m')
->join('listings AS l', 'm.user_id = l.member_id', 'left')
->join('groups AS g', 'm.group_id = g.group_id', 'left')
->group_by('m.user_id');
How can I continue to use this query if I wanted to do something like this:
if($query_total = $this->db->get()){
$this->total_results = $query_total->num_rows();
}
$this->db->limit($limit, $offset);
if($query_members = $this->db->get()){
return $query_members->result_array();
}
Update: In other words, I want to run a query with the get() method without clearing it from the query builder when it's done running so I can use the top part of the query later.
You can get it by using Active Record Caching (the last category on that page).
$this->db->start_cache(); // start caching
$this->db->select('m.user_id AS id, m.email_address, m.display_name, m.status, UNIX_TIMESTAMP(m.join_date) AS join_date,
l.listing_id, COUNT(l.member_id) AS total_listings,
g.group_id AS group_id, g.title AS group_title')
->from('users AS m')
->join('listings AS l', 'm.user_id = l.member_id', 'left')
->join('groups AS g', 'm.group_id = g.group_id', 'left')
->group_by('m.user_id');
$this->db->stop_cache(); // stop caching
Then you can use that query as much as you want.
if($query_total = $this->db->get()){
$this->total_results = $query_total->num_rows();
}
$this->db->limit($limit, $offset);
if($query_members = $this->db->get()){
return $query_members->result_array();
}
You can also flush the cache when you don't want that cached query anymore.
$this->db->flush_cache();
Hope it will be useful for you.
You are not passing any table name in $this->db->get() function.
Thank you
I wanted to know how to check whether there is a value present in a table (managers) and then add a 'yes' or 'no' string depending on if there is a value in that table or not.
$this->db->select('employees.first_name, employees.last_name, departments.department_name, departments.department_numb, titles.title');
$this->db->from('employees');
$this->db->where('first_name', $firstname);
$this->db->where('last_name', $lastname);
$this->db->join('department_manager', 'department_manager.emp_numb = employees.emp_numb', 'inner');
$this->db->join('departments', 'departments.department_numb = department_manager.department_numb', 'inner');
$this->db->join('titles', 'titles.emp_numb = employees.emp_numb', 'inner');
$this->db->where('department_name', $dept);
$this->db->where('title', $jobtitle);
$result = $this->db->get();
$data = array();
foreach($result->result() as $row)
{
$entry = array();
$entry['firstname'] = $row->first_name;
$entry['lastname'] = $row->last_name;
$entry['jobtitle'] = $row->title;
$entry['dept'] = $row->department_name;
$entry['deptid'] = $row->department_number;
//$entry['ismanager'] =
$data[] = $entry;
}
return $data;
I want to check whether an employee is present in the table 'department_manager' which is joined by an employees number. So if that employee number is not present in the table 'department_manager' then I want to insert in the array index $entry[ismanager'] a string which says 'no', and if the employee number is present in the table 'department_manager' then I want $entry['ismanager'] to hold the string 'yes'.
But I'm confused as to how to check that the employee is present or not in that table. Do I do it in the active record query or in the foreach loop? And if it is done in the foreach loop then how do I make that comparison as the query is completed?
Why have a field that is basically a calculated value? That's like having fields for quantity per box, quantity of boxes then saving the total items to a third field. Never save to the database something you can gain access to via a quick query. In your query above it's as simple as changing the dept manager join to a left join, including the dept manager id and saying if that field is blank in a record the person is not a manager. Using a LEFT join will return all records whether they have an entry in the management table or not.
Add: department_manager.emp_numb to the select.
The Join:
$this->db->join('department_manager', 'department_manager.emp_numb
= employees.emp_numb', 'left');
Then in the foreach:
if(!$row->department_manager.emp_numb)
{
this person is not a manager;
}
If you feel you really must have that extra field then you can still populate it with the method above.
If you are using MySQL, I think you are looking for:
IFNULL(expr1,expr2)
where:
expr1 == null condition (in your case NULL)
expr2 == replacement value
Source: Control Flow Functions
I can use:
Mage::getModel('cms/page')->getCollection()->addStoreFilter($store_id);
to retrieve a collection of CMS pages filtered by Store Id.
But how do I get it to remove ones which are also assigned to other stores?
ie: I do not want it to return items which have 'All Store Views' as the Store View. (Or any other additional store id assigned to that CMS page.) It has to only return pages unique to that one store.
I am extending the Aitoc permissions module, so that Store Admins cant view or edit CMS pages and static blocks which might impact other stores. This involves filtering those items from the grid.
There's no native collection method to do this, so you'll need to
Query the cms_page_store table for pages unique to a given store
Use the results from above in your filter
I didn't fully test the following, but it should work (and if it doesn't, it'll give you a good start on your own query)
$page = Mage::getModel('cms/page');
$resource = $page->getResource();
$read = $resource->getReadConnection();
#$select = $read->query('SELECT page_id FROM ' . $resource->getTable('cms/page_store') . ' GROUP BY store_id');
//set total count to look for. 1 means the page only appears once.
$total_stores_count_to_look_for = '1';
//get the table name. Need to pass through getTable to ensure any prefix used is added
$table_name = $resource->getTable('cms/page_store');
//aggregate count select from the cmd_page_store database
//greater than 0 ensures the "all stores" pages aren't selected
$select = $read->query('SELECT page_id as total
FROM '.$table_name.'
WHERE store_id > 0
GROUP BY page_id
HAVING count(page_id) = ?',array($total_stores_count_to_look_for));
//fetch all the rows, which will be page ids
$ids = $select->fetchAll();
//query for pages using IDs from above
$pages = Mage::getModel('cms/page')->getCollection()->addFieldToFilter('page_id',array('in'=>$ids));
foreach($pages as $page)
{
var_dump($page->getData());
}
If you have thousands and thousands of CMS pages it may be worth it to alter the cms/page collection's select to join in aggregate table data. I'll leave that as an exercise for the reader, as those sorts of joins can get tricky.
$collection = Mage::getModel('cms/page')->getCollection();
$collection->getSelect()
->join(
array('cps' => $collection->getTable('cms/page_store')),
'cps.page_id = main_table.page_id AND cps.store_id != 0',
array('store_id')
)
->columns(array('stores_count' => new Zend_Db_Expr('COUNT(cps.store_id)')))
->group('main_table.page_id')
->having('stores_count = ?', 1)
->having('cps.store_id = ?', $storeId)
;
Fusing some elements of the solutions proposed by Alan and Vitaly with my own cumbersome understanding, I achieved what I needed with the following code.
To put into context, I was extending the Aitoc permissions module, so that Store Admins cant view or edit CMS pages and static blocks which might impact other stores. This involved filtering those items from the grid.
$collection = Mage::getModel('cms/page')->getCollection();
$collection->addStoreFilter(Mage::helper('aitpermissions')->getStoreIds());
$conn = Mage::getSingleton('core/resource')->getConnection('core_read');
$page_ids = array();
foreach($collection as $key=>$item) {
$page_id = $item->getId();
$results = $conn->fetchAll("SELECT * FROM cms_page_store
WHERE page_id = ".$page_id.";");
$count = 0;
$arr_stores = array();
foreach($results as $row) {
$arr_stores[] = $row['store_id'];
$count++;
}
//We dont want to show the item if any of the following are true:
//The store id = 0 (Means its assigned to All Stores)
//There is more than one store assigned to this CMS page
if( in_array('0',$arr_stores) || $count>1) {
//This removes results from the grid (but oddly not the paging)
$collection->removeItemByKey($key);
}
else {
//build an array which we will use to remove results from the paging
$page_ids[] = $page_id;
}
}
//This removes results from paging (but not the grid)
$collection->addFieldToFilter('page_id',array('in'=>$page_ids));
I'm not sure why I needed to use two different methods to filter from the paging and the grid.
The site uses magento 1.5 so perhaps there is an issue related to that.
Either way, this solution worked for me.
My solution to add field store_id to pages collection via join, and use collection method addFieldToFilter().
$pages = Mage::getModel('cms/page')->getCollection();
$pages->getSelect()->joinInner(
array('cms_page_store' => 'cms_page_store'),
'main_table.page_id = cms_page_store.page_id',
array()
);
$pages->addFieldToFilter('store_id', ['in' => [1, 2]]);
How can I select rows from two or more tables?
I'm setting default fields for a form, and I need values from two tables...
My current code reads:
$this->CI->db->select('*');
$this->CI->db->from('user_profiles');
$this->CI->db->where('user_id' , $id);
$user = $this->CI->db->get();
$user = $user->row_array();
$this->CI->validation->set_default_value($user);
The example in the User Guide should explain this:
$this->db->select('*'); // <-- There is never any reason to write this line!
$this->db->from('blogs');
$this->db->join('comments', 'comments.id = blogs.id');
$query = $this->db->get();
// Produces:
// SELECT * FROM blogs
// JOIN comments ON comments.id = blogs.id
See the whole thing under Active Record page in the User Guide.
Just add the other table to the "->from()" method. Something like:
$this->db->select('t1.field, t2.field2')
->from('table1 AS t1, table2 AS t2')
->where('t1.id = t2.table1_id')
->where('t1.user_id', $user_id);
I think the question was not so much about joins as how to display values from two different tables - the User Guide doesn't seem to explain this.
Here's my take:
$this->db->select('u.*, c.company, r.description');
$this->db->from('users u, company c, roles r');
$this->db->where('c.id = u.id_company');
$this->db->where('r.permissions = u.permissions');
$query = $this->db->get();
I think the syntax is incorrect.
You need to select one record. I have two tables, and I have an id from one table transfer by parameter, and the relation of both tables.
Try this
$this->db->select('*')
->from('student')
->where('student.roll_no',$id)
->join('student_details','student_details.roll_no = student.roll_no')
->join('course_details','course_details.roll_no = student.roll_no');
$query = $this->db->get();
return $query->row_array();
$SqlInfo="select a.name, b.data fromtable1 a, table2 b where a.id=b.a_id";
$query = $this->db->query($SqlInfo);
try this way, you can add a third table named as c and add an 'and' command to the sql command.
// Select From Table 1 All Fields, and From Table 2 one Field or more ....
$this->db->select('table1.*, table2.name');
$this->db->from('table1, table2');
$this->db->where('table2.category_id = table1.id');
$this->db->where('table2.lang_id',$id); // your where with variable
$query = $this->db->get();
return $query->result();