I have two tables:
MENU
->id_menu
->title
->page_id
->order
PAGES
->id_page
->title
->page
->slug
This is select function:
public function get_all_menu()
{
return $this->db
->select('menu.*, pages.id_page, pages.title AS page_title')
->from($this->table)
->join('pages','id_page = page_id')
->order_by($this->order_by)
->get()
->result_array();
}
Here is my problem - item in the menu can be connected with page, but also it can be solo (without connection to page). This means page_id in MENU table can be 0. If page_id is 0, I am not getting that row from above query. How can I get all items in the menu (those which are connected and those which are not connected with page )?
You need add the join type in ->join()
like
public function get_all_menu()
{
return $this->db
->select('menu.*, pages.id_page, pages.title AS page_title')
->from($this->table)
->join('pages','id_page = page_id','left')
->order_by($this->order_by)
->get()
->result_array();
}
See reference manual Active Record
As requested from comments:
You need to use "LEFT JOIN" to retrieve partial or incomplete values from the tables.
In this case, the regular join is looking the matches between the two tables. Since there's no id 0 in one of the tables, the match can't be retrieved and the row won't be selected.
Using a LEFT JOIN (or RIGHT JOIN when appropriate, based on which one is the "incomplete" table) if the match isn't retrieved, the outcome will contain also the rows which aren't matched, with all NULLs in the other table's values
From Your Controller call this method in Model Say your Model Name is general_model
$value=('menu.*, pages.id_page, pages.title AS page_title');
$joins = array
(
array
(
'table' => 'pages',
'condition' => 'menu.id_page = pages.page_id',
'jointype' => 'leftouter'
),
);
$where_condition=array('menu.Id '=>'Enable','restaurant.Id'=>$rest_id);
$data['detail'] = $this->general_model->get_joins('menu',$value,$joins,$where_condition,'menu.Id','asc')->result();
here $where_condition is a where condition you want to pass if u want to remove you can remove it from function.,And Last two parameters are orderby
Simply use this function in your Model For Join
public function get_joins($table,$value,$joins,$where,$order_by,$order)
{
$this->db->select($value);
if (is_array($joins) && count($joins) > 0)
{
foreach($joins as $k => $v)
{
$this->db->join($v['table'], $v['condition'], $v['jointype']);
}
}
$this->db->order_by($order_by,$order);
$this->db->where($where);
return $this->db->get($table);
}
Related
I have a challenge for a job and my mission is to perform a CRUD using codeigniter. And in this challenge, I have to make a listing of two MYSQL tables, one with the name "deliverer" and the other "address".
The problem is that I am not able to make the connection in the database with the two tables. I'll show you how my Controller and my Model are.
Model:
public function SelecionaTodos() {
$retorno = $this->db->get('entregador',100); *I NEED TO CONNECT THE DELIVERY TABLE AND ADDRESS *
return $retorno->result();
}
Controller:
public function index() {
$this->load->model('EntregadorModel');
$tabela = $this->EntregadorModel->SelecionaTodos();
$dados = array(
'titulo' => 'Lista de Entregadores',
'tabela' => $tabela,
'pagina' => 'entregador/index.php'
);
$this->load->view('index',$dados);
}
$this->db->join()
Permits you to write the JOIN portion of your query:
$this->db->select('*');
$this->db->from('deliverers'); //Lista de Entregadores
$this->db->join('address', 'address.id = deliverer.id');
foreach($query->result() as $result){
echo $result->deliverer;
echo $result->address;
}
// Produces:
// SELECT * FROM deliverer ON deliverer.id = address.id
Multiple function calls can be made if you need several joins in one query.
If you need a specific type of JOIN you can specify it via the third parameter of the function. Options are: left, right, outer, inner, left outer, right outer and full outer.
also you can check : Join two tables display category name and list all items and Join not working with columns same name and id
It was working just fine, but I had to import data afresh in the existing order1 table which is related to order_item table on order.id = order_item.order_id and order_item.location_id = location.id
So to get the location in GridView of order1 table I had relation defined like so:
public function getLocation() {
return $this->hasOne(Location::className(), ['id' => 'location_id'])->viaTable('{{%order_item}}', ['order_id' => 'id']);
}
Now I have multiple records in the GridView. The query formed for the GridView is like:
SELECT `order1`.*
FROM `order1`
LEFT JOIN `order_item` ON `order1`.`id` = `order_item`.`order_id`
LEFT JOIN `location` ON `order_item`.`location_id` = `location`.`id`
where 1 ORDER BY `id` DESC
LIMIT 20;
How I can fix this as inner join or otherwise, so that it returns records only once from order1 table?
In GridView I am using location.location_title.
Note: there are multiple order items per order.
also Tried:
public function getOrderItem()
{
return $this->hasMany(OrderItem::className(), ['order_id' => 'id']);
}
public function getLocation()
{
return $this->hasOne(Location::className(), ['id' => 'location_id'])
->via('orderItem');
}
You need to add GROUP BY in your search model to ensure that orders will not be duplicated in query results:
$query->groupBy('order1.id');
Although hasOne() seems to be incorrect (if one order can have multiple items, then it could also have multiple locations), changing this to hasMany() will not fix GridView results. You need to be careful with one-to-many or many-to-many relations, usually you need to use GROUP BY to remove duplicates or adjust your DB structure or joins in search model, to avoid such situation.
BTW: Adding groupBy() in relation definition (getLocation()) is almost always incorrect. This is not a job of relation definition to handle grouping of main model results (you can be almost sure it will create issues with lazy loading).
I have two related tables, posts and hidden_posts, where posts.id corresponds to hidden_posts.post_id.
In my posts model I have this relation to return a record if the post should be hidden:
public function getHiddenPosts()
{
return $this->hasOne(HiddenPost::className(), ['post_id' => 'id']);
}
Now I need to return all posts that are NOT hidden. So I am looking for the equivalent of this pseudo code:
return $this->hasNone(HiddenPost::className(), ['post_id' => 'id'])->all();
Which is saying, "show me all posts that are not in the hidden_posts table".
So does this use an outer join query or is there a statement that I can't find do do this in one line?
You can do it this way. Get all posts that are not listed in Hidden table:
$posts = Post::find()
->andFilterWhere(['not in',
'post.id',
HiddenPost::find()
->select(['hidden_post.post_id'])
->all();
In any case, it is best to proceed from the raw SQL statement. Write a statement that satisfies your results and transfer it to ActiveRecord query.
Post items could be retrieved using an inner join
$res = Post::find()
->select('post.*')
->innerJoin('hdn_post', '`post`.`id` = `hdn_post`.`post_id`')
->all();
It could be good practice using yii2 owned function instead of adding queries inside the model such as using select queries in your model.
Instead you can use ORM functions in yii2 has already done by gii inner functions created for to make u=your work easy.
Add * #property YourModel $hidden_post
and inside this model add you post_id such as ( * #property integer $post_id ) to create relation.
public function getHiddenPosts($hidden_post) {
return $this->find()->joinWith('hidden_post')
->where(['hidden_post' => $hidden_post])
->all();
}
You could retrive the Post items using an inner join
$posts = Post::find()
->select('post.*')
->innerJoin('hidden_post', '`post`.`id` = `hidden_post`.`post_id`')
->all();
for not hidden then use left join and check for null result of related table
$posts = Post::find()
->select('post.*')
->leftJoin('hidden_post', '`post`.`id` = `hidden_post`.`post_id`')
->where('ISNULL(`hidden_post`.console_id)')
->all();
I have two models: Users, Posts. User has many posts.
public function getPosts()
{
return $this->hasMany(Posts::className(), ['user_id' => 'id']);
}
I need to get only those users who have posts (posts>0).
How do I write query?
Users:find()->where(['>', 'posts', 0])->all()
The code above doesn't work.
Try This query :
Users:find()
->where('id IN (select user_id FROM posts GROUP BY user_id)')
->all();
To get users with at least one post you need to use INNER JOIN:
Users::find()
->innerJoinWith('posts', false)
->groupBy('users.id')
->all();
It should be more efficient that subquery.
If you want to filter by number of posts, you should add HAVING clause with count condition:
Users::find()
->innerJoinWith('posts', false)
->groupBy('users.id')
->having(new \yii\db\Expression('COUNT(*) > :posts_nr', ['posts_nr' => 2]))
->all();
But such queries may be really heavy on large databases - you should consider adding additional column with posts count to users table.
$orders = Users::find()->with('posts')->all();
Inner join should remove users where posts are null
I have tables Ads with column AdsId,ClientId and table Assigned . Assigned has AdsId as foreign key. I want to count the number of AdsId in Assigned for given ClientId. I have the following query which works but I am not sure if its the best way. How can I run the same query in yii? Hope I made my question clear.
SELECT A. * , (
SELECT COUNT( B.AdsId )
FROM Assigned AS B
WHERE B.AdsId = A.AdsId
AND A.ClientId =1
)
FROM Ads AS A
WHERE A.ClientId =1
LIMIT 0 , 30
First declare a relation in your model relations function
public function relations(){
return array(
...
'AdsIdCount'=> array(self::STAT,'Ads','AdsId'),
//'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...additional options)
);
}
then in your in returned activeRecord results you can just call this count like this
$result = Assigned::model()->find($criteria);
$result->adsIdCount ; // do logic here
or
$results = Assigned::model()->findAll($criteria);
foreach ($results as $result){
$result->adsIdCount ; // do logic here
}
see STAT relation for more details on how this works http://www.yiiframework.com/doc/guide/1.1/en/database.arr#statistical-query