Nested joins in Codeigniter - php

How to run this sql query in Codeigniter framework?
SELECT users.*,
GROUP_CONCAT(category.title SEPARATOR ',') as title
FROM users
LEFT JOIN (
procducts as pr
INNER JOIN category ON pr.category_id =category.id
)
ON (users.id=pr.user_id)
GROUP BY users.id
using Active Record (Query Builder Class) in Codeigniter without using db->query

The Codeigniter docs explain a join like follows:
join($table, $cond[, $type = ''[, $escape = NULL]])
there is no documentation on nested join support. So you could create a query like:
$this->db->select('users.*, GROUP_CONCAT(category.title SEPARATOR ',') as title')
->from('users')
->join('procducts as pr INNER JOIN category ON pr.category_id =category.id','users.id=pr.user_id','left')
->group_by('users.id');
$query = $this->db->get();

i use this code
$this->db->select("
users.*,GROUP_CONCAT(category.title SEPARATOR ',')
as title FROM users LEFT JOIN
(procducts as pr INNER JOIN category ON
pr.category_id =category.id)
ON (users.id=pr.user_id)");
$this->db->group_by("users.id");
and this code it's ok,and without any problem .

Related

MySQLi inner join not working properly

I have a query that select shows alongside with it's rating. But it will not work if there isn't any rates. I want it to work even when it finds zero results on the rating table.
My query is
$shows = $DB->query('SELECT
p.id, p.title, p.cover, p.summary, p.genre, p.year,
ROUND(AVG(pr.rating), 1) AS rating_average
FROM shows p
INNER JOIN shows_ratings pr
ON pr.showid = p.id');
Change inner join with left join.
Explanation: You are trying to join two table on key which doesn't exist in other table, that's why you are not getting any result in inner join. Whereas left join will return rating as empty when key is not present in rating table.
$shows = $DB->query('SELECT
p.id, p.title, p.cover, p.summary, p.genre, p.year,
ROUND(AVG(pr.rating), 1) AS rating_average
FROM shows p
LEFT JOIN shows_ratings pr
ON pr.showid = p.id');

Making query with multiple join's

I'm now learning php and codeigniter and now I want to combine query to be fast and effective. I have made all, but haven't joined the last table...
I have 4 tables: posts, users, post_categories, categories;
And what I want to get:
All posts
User info using usr_id
Get all categories id from post_categories using cat_ids
And get each name of category using id_*
This is what I end up... it's not complete because I've got stuck with getting categories name for each of id_*
$data = $this->db->select('p.*, u.nickname, u.usr_status, u.usr_rating, pc.*')
->from('posts p')
->join('users u', 'p.usr_id = u.id', 'left')
->join('post_categories pc', 'p.cat_ids = pc.id', 'left')
->limit($limit, $start)
->order_by('p.id', 'desc')
->where('p.active', 1)
->get()
->result_array();
Anyone could help me to end up this query in codeigniter?
edit:
in post_categories: id_1 always will be... but id_2 and id_3 could stay as NULL(default value)
Something like the following SQL query should work for you...
SELECT
posts.*,
users.nickname, users.user_status, users.usr_rating,
c1.category as category_1,
c2.category as category_2,
c3.category as category_3
FROM posts
INNER JOIN users ON user.id = posts.user_id
INNER JOIN post_dategories ON post_categories.id = posts.cat_ids
INNER JOIN categories c1 ON post_categories.id_1 = c1.id
LEFT JOIN categories c2 ON post_categories.id_2 = c2.id
LEFT JOIN categories c3 ON post_categories.id_3 = c3.id
WHERE posts.active = 1
NOTE: LEFT JOIN on c2 and c3 because you said they were optional

Joining 4 tables with Mysql and Codeigniter

I have 4 tables, that's all in a relationship, yes they love each other :p
Products
Product Categories
Product Category Relationships
Product Images
I want to join these 4 tables in one query, here is my Codeigniter code to do this;
function list_products($limit = 10, $offset = 0, $category)
{
$this->db->select('p.url, p.name, p.title, i.image');
$this->db->from('products p');
$this->db->join('product_categories c','c.id = r.category_id',
'left');
$this->db->join('product_category_relations r',
'r.category_id = c.id','left');
$this->db->join('product_images i',
'p.id = i.product_id AND i.default = 1','left');
$this->db->where('c.url',$this->category_url.$category);
$this->db->limit($limit,$offset);
return $this->db->get()->result();
}
When i execute this function / query, the result is an error about defining "r".
Unknown column 'cms_r.category_id' in 'on clause'
The query:
SELECT p.url, p.name, p.title, i.image FROM
(cms_products p) LEFT JOIN cms_product_categories c ON c.id =
cms_r.category_id LEFT JOIN cms_product_category_relations r ON
r.category_id = c.id LEFT JOIN cms_product_images i ON
p.id = i.product_id AND i.default = 1 WHERE c.url =
'kategori/yilbasi' LIMIT 12
Can you help me?
You assign r to be similar to product_category_relations after you use it.
Here you write:
$this->db->join('product_categories c','c.id = r.category_id','left');
But what is r? You answer this question only in the next statement.
$this->db->join('product_category_relations r','r.category_id = c.id','left');
Provide sample SQL Create script, if you want concrete answer.
#Edward Ruchevits your query does not join because of r.category_id define after joining of product_category_relations r, you need Relationships between products and product_categories then your query something be like
$this->db->join('product_categories c','c.product_id = p.id','left');

SQL Join question, return null if second table is empty

I have 2 tables.
table 1 (projects): id, name, type
table 2 (project_ratings): project_id, rating
Some projects don't have ratings.
SELECT `p`.`id`, `p`.`name`, AVG(pr.rating) FROM (`projects` p) JOIN `project_ratings` pr ON `p`.`id` = `pr`.`project_id` WHERE `p`.`type` = 'group' OR `p`.`type` = 'user';
I want to return all projects, and return NULL if there aren't any ratings. This query returns only the ones with ratings.
I tried left join, right join, full join, still same thing.
Using CodeIgniter Active Records:
$this->db->select("p.id, p.name, AVG(pr.rating)");
$this->db->from('projects p');
$this->db->join('project_ratings pr', 'p.id = pr.project_id');
$this->db->where('p.type', 'group');
$this->db->or_where('p.type', 'user');
$res = $this->db->get();
what am I missing?
When using an aggregate function (AVG() in this case), you need to specify a GROUP BY clause with the non-aggregate fields, eg
GROUP BY p.id, p.name
To ensure all project references are present regardless of joined ratings, use a LEFT JOIN.
The sql that you want would be
SELECT *
FROM projects
LEFT OUTER JOIN project_ratings ON projects.id = project_ratings.project_id
I'm not certain how to do that with code igniter.
Try this:
$this->db->select("p.id, p.name, AVG(pr.rating) as average_rating");
$this->db->from('projects p');
$this->db->join('project_ratings pr', 'p.id = pr.project_id', 'left');
$this->db->where('p.type', 'group');
$this->db->group_by('p.id');
$this->db->or_where('p.type', 'user');
$res = $this->db->get();
If there is no rating, average_rating will be NULL.
Query should be:
SELECT `p`.`id`, `p`.`name`, AVG(pr.rating)
FROM (`projects` p)
LEFT OUTER JOIN `project_ratings` pr ON `p`.`id` = `pr`.`project_id`
WHERE `p`.`type` = 'group' OR `p`.`type` = 'user';
(I don't know how to do that in CodeIgniter :)
You can get an outer join by do this:
$this->db->join('project_ratings pr', 'p.id = pr.project_id', 'outer');

Doctrine 2 QueryBuilder vs Handcoded DQL - different results

I have Doctrine2 DQL query but I want to build it with QueryBuilder, I have noticed that produced DQL is somewhat different from the handcrafted one, and I'm wondering what am I missing here - maybe I'm not aware of something or doing things wrong way?
Ok, some details:
My handcrafted query looks like this:
select count(fi.id)
from Entities\Content\FolderLookup fl
join fl.site fls
join fl.folder flf,
Entities\Content\FolderItem fi
join fi.site fis
join fi.folder fif
join fi.item it
join it.type tp
join it.content ic
where fl.namePath = ?1
and tp.name = ?2
and fls.id = fis.id
and flf.id = fif.id
Now, I'm trying to reproduce it like this with QueryBuilder:
$qb->select("count(fi.id)")->from("Entities\Content\FolderLookup", "fl")->join("fl.site","fls")->join("fl.folder", "flf");
$qb->from("Entities\Content\FolderItem","fi")->join("fi.site","fis")->join("fi.folder","fif");
$qb->join("fi.item","it")->join("it.type","tp")->join("it.content","ic");
$wherePart = $qb->expr()->andx();
$wherePart->add($qb->expr()->eq("fl.namePath","?1"));
$wherePart->add($qb->expr()->eq("tp.name","?2"));
$wherePart->add($qb->expr()->eq("fls.id","fis.id"));
$wherePart->add($qb->expr()->eq("flf.id","fif.id"));
$qb->where($wherePart);
This however is producing this DQL query:
SELECT count(fi.id) FROM Entities\Content\FolderLookup fl,
Entities\Content\FolderItem fi
INNER JOIN fl.site fls
INNER JOIN fl.folder flf
INNER JOIN fi.site fis
INNER JOIN fi.folder fif
INNER JOIN fi.item it
INNER JOIN it.type tp
INNER JOIN it.content ic
WHERE (fl.namePath = ?1)
AND (tp.name = ?2)
AND (fls.id = fis.id)
AND (flf.id = fif.id)
As you can see there is part of this missing comapring to handcrafted one (First line):
fl join fl.site fls join fl.folder flf
I'm not sure why these joins are missing as I am defining them here:
$qb->select("count(fi.id)")->from("Entities\Content\FolderLookup", "fl")->join("fl.site","fls")->join("fl.folder", "flf");
Update:
The fun part starts, when DQL gets translated into SQL - in this case MySQL:
Handcrafted one becomes:
SELECT count(f0_.id) AS sclr0 FROM FolderLookup f1_ INNER JOIN Site s2_ ON f1_.site_id = s2_.id INNER JOIN Folder f3_ ON f1_.folder_id = f3_.id, FolderItem f0_ INNER JOIN Site s4_ ON f0_.site_id = s4_.id INNER JOIN Folder f5_ ON f0_.folder_id = f5_.id INNER JOIN Item i6_ ON f0_.item_id = i6_.id INNER JOIN ItemType i7_ ON i6_.type_id = i7_.id INNER JOIN ItemContent i8_ ON i6_.content_id = i8_.id WHERE f1_.namePath = ? AND i7_.name = ? AND s2_.id = s4_.id AND f3_.id = f5_.id
Where generated one looks like this:
SELECT count(f0_.id) AS sclr0 FROM FolderLookup f1_, FolderItem f0_ INNER JOIN Site s2_ ON f1_.site_id = s2_.id INNER JOIN Folder f3_ ON f1_.folder_id = f3_.id INNER JOIN Site s4_ ON f0_.site_id = s4_.id INNER JOIN Folder f5_ ON f0_.folder_id = f5_.id INNER JOIN Item i6_ ON f0_.item_id = i6_.id INNER JOIN ItemType i7_ ON i6_.type_id = i7_.id INNER JOIN ItemContent i8_ ON i6_.content_id = i8_.id WHERE (f1_.namePath = ?) AND (i7_.name = ?) AND (s2_.id = s4_.id) AND (f3_.id = f5_.id)
And this is invalid statement, as database returns with:
Column not found: 1054 Unknown column 'f1_.site_id' in 'on clause'
Any ideas welcome.
It seems the DQL parser is wrongly positioning the joins to the wrong from.
My initial suggestion is to try to make only 1 FROM item and a subselect.
Also, I'd love if you add the same content you asked here in our bug tracking: http://www.doctrine-project.org/jira/browse/DDC
Thanks a lot!
Guilherme Blanco
Doctirne Core Developer
they are not missing. just reordered
INNER JOIN fl.site fls
INNER JOIN fl.folder flf

Categories