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
Related
I have show (only show, not compleate CRUD) the result of a query which is built as following:
SELECT SUM(a) AS ab, b, COUNT(*) as C
FROM x
INNER JOIN y
ON y.a = x.a
WHERE b=123
GROUP BY b
so I built this query with ActiveRecord in SearchModels search() method.
In the model of table a I added a hasOne()-relation.
To display the data of this query, I'm using GridView. In it's columns array I use y.b and so on...
My problem: The columns from table x are displayed correct, but for every "joined column" from table y it displays (not set).If I print the by ActiveRecord builded query, and execute it in my sql client, it displays all data. I guess this is depending on the Models primaryKey() function, but I can't change it to get the table work properly. Does somebody know a solution for my problem or why dataProvider/GridView takes care of the selected model's (in this case model of table x) primaryKey() method (or how to make dataProvider/GridView ignore the primaryKey()?
In model you should create relation method with relation model.
For example:
class Patient extends ActiveRecord
{
public function getOrders()
{
return $this->hasMany(Order::class, ['patient_id' => 'id']);
}
}
class Order extends ActiveRecord
{
public function getPatient()
{
return $this->hasOne(Patient::class, ['id' => 'patient_id']);
}
}
For access data:
// SELECT * FROM `patient` WHERE `id` = 1
$patient = Patient::findOne(1);
$orders = $patient->orders;
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();
function get_all_notification() { //get all notification based on the 'notification' table left join by 'membership' table
$this->db->select()->from('notification')->join('membership','membership.membership_id = notification.notif_id','left'); $notif = $this->db->get();
return $notif->result();
}
I cannot display the fields from membership table.
Try this
function get_all_notification() { //get all notification based on the 'notification' table left join by 'membership' table
$this->db->select('*')->from('notification')->join('membership','membership.membership_id = notification.notif_id','left');
$notif = $this->db->get();
return $notif->result();
}
function get_all_notification()
{
$this->db->select('n.*,m.*');
$this->db->from('notification as n')
$this->db->join('membership as m','m.membership_id = n.notif_id','left');
$notif = $this->db->get();
return $notif->result();
}
This is used when you want a clean code that's from top to bottom. But using your code is fine to where as the arrows are continuous. You just forgot to identify which fields to select. Also using aliases are good in selecting specific fields.
as you can see, I used n.* and m.*, this is just a wildcard to select all from the n table and m. you can you n.your_field and m.your_field when specifying what you want.
Goodluck and have fun coding :D
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);
}