I want to convert this sql query for the entity manager of doctrine :
SELECT count(c.id)
FROM content c
WHERE c.id IN
(SELECT tdtc.content_id
FROM tdtheme_content tdtc
JOIN tdtheme tdt ON tdtc.tdtheme_id = tdt.id
JOIN td t ON tdt.td_id = t.id
JOIN matiere m ON t.matiere_id = m.id
WHERE m.id = 2)
OR c.id IN
(SELECT sc.content_id
FROM semaine_content sc
JOIN semaine s ON sc.semaine_id = s.id
JOIN cour cr ON s.cour_id = cr.id
JOIN matiere m ON cr.matiere_id = m.id
WHERE m.id = 2)
OR c.id IN
(SELECT ac.content_id
FROM annale_content ac
JOIN annale a ON ac.annale_id = a.id
JOIN matiere m ON a.matiere_id = m.id
WHERE m.id = 2)');
I have :
Matiere With Annale And Td And Cours
Annale With Contents
Td With Tdtheme With Contents
Cours With Semaines With Contents
And I want to get count of contents for one matiere
Any Idea ?
Thanks and sorry for my bad English ^^
Assuming your entity names are Content, TdTheme_Content, etc.
$repo = $em->getRepository('AppBundle:Content');
$query = $repo ->createQueryBuilder('c');
$subQuery1 = $query->createSubquery();
$subQuery1
->select('tdtc.contentId')
->from('TdTheme_Content tdtc')
->join('tdtc.tdTheme tdt') // Doctrine joins by property names, not column names
->join('tdt.td t')
->join('t.matiere m')
->where('m.id = ?', 2)
;
// Assume similar for $subQuery2 and $subQuery3
$query
->select('COUNT(c.id)')
->where('c.id IN(' . $subQuery1->getDql() ')')
->orWhere('c.id IN(' . $subQuery2->getDql() ')')
->orWhere('c.id IN(' . $subQuery3->getDql() ')')
;
NOTE: I did not debug this or attempt to execute it - this was just off the top of my head with some basic knowledge of the doctrine query-builder api.
Related
I have written a SQL query which works fine and output provides all the data that I need:
Please see this screenshot:
This is the SQL code:
SELECT
P.name, C.project_id, C.choice_id, C.time_stamp, P.id,
P.description, T.type, P.activated
FROM
(SELECT P.*
FROM aqoru_pt_project P
JOIN
(SELECT id, MAX(creation_date) AS latestUpdate
FROM aqoru_pt_project
GROUP BY id) t ON t.id = P.id AND t.latestUpdate = P.creation_date) P
JOIN
(SELECT C.*
FROM aqoru_pt_project_choice C
JOIN
(SELECT project_id, MAX(time_stamp) AS latestDate
FROM aqoru_pt_project_choice
GROUP BY project_id) t ON t.project_id = C.project_id AND t.latestDate = C.time_stamp) C ON P.id = C.project_id
LEFT JOIN
aqoru_community_groups_members CGM ON P.group_id = CGM.groupid
INNER JOIN
aqoru_pt_project_type T ON P.type_id = T.id
WHERE
P.user_id = 569 OR CGM.memberid = 569
AND CGM.permissions = 1
AND P.deactivated != 1
GROUP BY
P.id
ORDER BY
P.id;
Now I need to push it into php format I was trying without great success as I am struggling mainly with the part where I try to put Join in select on the very beginning of the code. Definitely the part after ON P.id = C.project_id works fine. The problem occurs when I try to add max value from other table.
This is the code I wrote, but it does not work:
public function getProjects($userID)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$columns = array('P.id', 'P.name', 'P.description', 'T.type', 'P.activated');
$query
->select(array('P.id', 'P.name', 'P.description', 'T.type', 'P.activated', 'max(C.time_stamp) as max'))
->from($db->quoteName(
->SELECT ('P.*')
->FROM ($db->quoteName('aqoru_pt_project', 'P')
->JOIN($db->quoteName(
->SELECT ('id', 'MAX(creation_date) AS latestUpdate')
->FROM ($db->quoteName('aqoru_pt_project')
->group($db->quoteName('id')) 't' . ' ON t.id = P.id AND t.latestUpdate = P.creation_date') P
->JOIN(
->SELECT ('C.*')
->FROM ($db->quoteName('aqoru_pt_project_choice', 'C')
->JOIN($db->quoteName(
->SELECT ('project_id', 'MAX(time_stamp) AS latestDate')
->FROM ($db->quoteName('aqoru_pt_project_choice'))
->group($db->quoteName('id')) 't' . ' ON t.project_id = P.project_id AND t.latestUpdate = P.time_stamp') 'C' . 'ON P.id = C.project_id'
))
->leftjoin($db->quoteName('#__community_groups_members', 'CGM') . ' ON P.group_id = CGM.groupid')
->innerjoin($db->quoteName('#__pt_project_type', 'T') . ' ON P.type_id = T.id')
->where(
$db->quoteName('P.user_id') . ' = ' . $db->quote($userID),
)
->orwhere(array(
$db->quoteName('CGM.memberid') . ' = ' . $db->quote($userID),
$db->quoteName('CGM.permissions') . ' = 1'
))
->andwhere($db->quoteName('P.deactivated') . ' != 1')
->group($db->quoteName('P.id'))
->order('P.id DESC');
/*
* Note: for some reason the queries return duplicates on the production site not on my local site
* So we must group by projectID to avoid duplicates. I am not aware what is causing this duplication
*/
return $db->setQuery($query)->loadObjectList();
}
try this
$this->db->select('P.name,C.project_id,C.choice_id,C.time_stamp,P.id,P.description,T.type,P.activated')
->from('(SELECT P.*
FROM aqoru_pt_project P
JOIN
(SELECT id, MAX(creation_date) AS latestUpdate
FROM aqoru_pt_project
GROUP BY id) t ON t.id = P.id AND t.latestUpdate = P.creation_date) P')
->join('(SELECT C.*
FROM aqoru_pt_project_choice C
JOIN
(SELECT project_id, MAX(time_stamp) AS latestDate
FROM aqoru_pt_project_choice
GROUP BY project_id) t ON t.project_id = C.project_id AND t.latestDate = C.time_stamp) C', 'P.id = C.project_id')
->join('aqoru_community_groups_members CGM', 'P.group_id = CGM.groupid', 'LEFT')
->join('aqoru_pt_project_type T', 'P.type_id = T.id')
->where('P.user_id', 569)
->or_where('CGM.memberid', 569)
->where('CGM.permissions', 1)
->where('P.deactivated !=', 1)
->group_by('P.id')
->order_by('P.id ASC')
->get();
So I have a prepared SQL query (below) that joins 4 tables together based on the user's ID. The final relationship however is a one to many (a user can have more than one skill) so I need all rows returned where the skill ID equals the user ID. At the moment only the first row that matches the user ID in the freelancer_skill table returns. How do I get all rows to return?
SELECT
u.user_id, u.firstname, u.lastname, u.email, u.bio, u.portfolio, u.location, u.time_joined, u.image_location,
f.freelancer_id, f.jobtitle, f.priceperhour,
ut.*,
ft.testimonial, ft.testimonial_source,
fs.skill, fs.skill_rating
FROM ((((users AS u
LEFT JOIN freelancers AS f
ON u.user_id = f.freelancer_id)
LEFT JOIN user_types AS ut
ON u.user_id = ut.user_type_id)
LEFT JOIN freelancer_testimonials AS ft
ON u.user_id = ft.testimonial_id)
LEFT JOIN freelancer_skills AS fs
ON u.user_id = fs.skill_id)
WHERE
u.confirmed = :confirmed
AND u.user_id = :userID
AND ut.user_type = :userType
AND u.granted_access = :grantedAccess
EDIT
Updated code with user type WHERE clause moved into join:
SELECT
u.firstname, u.lastname, u.email, u.bio, u.portfolio, u.location, u.time_joined, u.image_location,
f.jobtitle, f.priceperhour,
ut.user_type,
ft.testimonial, ft.testimonial_source,
fs.skill, fs.skill_rating
FROM ((((" . DB_NAME . ".users AS u
LEFT JOIN " . DB_NAME . ".freelancers AS f
ON u.user_id = f.freelancer_id)
LEFT JOIN " . DB_NAME . ".user_types AS ut
ON u.user_id = ut.user_type_id AND ut.user_type = :userType)
LEFT JOIN " . DB_NAME . ".freelancer_testimonials AS ft
ON u.user_id = ft.testimonial_id)
RIGHT JOIN " . DB_NAME . ".freelancer_skills AS fs
ON u.user_id = fs.skill_id)
WHERE
u.confirmed = :confirmed
AND u.user_id = :userID
AND u.granted_access = :grantedAccess
To fetch the results I am using fetch (below). I've tried using fetchALL which does return each skill a user holds but also returns duplicates of their data for each skill.
$results->execute();
$user = $results->fetch(PDO::FETCH_ASSOC);
return $user;
Here is an SQLFiddle: http://sqlfiddle.com/#!2/d7bb3/4
You have a filter in the wrong place. You are declaring a left join to user_types but are filtering on that table in the where clause. That makes it an implicit inner join. Move
and ut.user_type = :userType
to follow this:
LEFT JOIN user_types AS ut ON u.user_id = ut.user_type_id
That might be the cause of your problem, but even if it's not, you will still get unexpected results with that filter in the where clause.
change the order of the joins. Swap the Users table and freelancer_skills table.
-This apparently does not work.
Maybe try something like this instead. Not ideal if you want to list a hundred skills for one person.
SELECT
u.firstname,
u.lastname,
u.email, u.bio, u.portfolio, u.location, u.time_joined, u.image_location,
f.jobtitle, f.priceperhour,
ut.user_type,
ft.testimonial, ft.testimonial_source,
count(case when fs.skill = 'HTML5' then 1 end) as HTML5,
count(case when fs.skill = 'CSS3' then 1 end) as CSS3,
count(case when fs.skill = 'PHP' then 1 end) as PHP,
fs.skill_rating
FROM
(
(
(
(
users AS u
LEFT JOIN freelancers AS f ON
u.user_id = f.freelancer_id
)
LEFT JOIN user_types AS ut ON
u.user_id = ut.user_type_id AND
ut.user_type = 'developer'
)
LEFT JOIN freelancer_testimonials AS ft ON
u.user_id = ft.testimonial_id
)
RIGHT JOIN freelancer_skills AS fs ON
u.user_id = fs.skill_id
)
WHERE
u.confirmed = '1'
AND u.user_id = '3'
AND u.granted_access = '1'
group by
u.firstname,
u.lastname,
u.email, u.bio, u.portfolio,
u.location,
u.time_joined, u.image_location,
f.jobtitle, f.priceperhour,
ut.user_type,
fs.skill_rating
This is my repository's function's code:
public function findLatest($count, $page)
{
return $this->getEntityManager()
->createQuery
('
SELECT
n.id, n.createdAt, n.title, n.titleCanonical, n.entry, n.movie,
c.title as category,
i as images,
COUNT(com.id) as numberOfComments
FROM WisJaCoreBundle:News n
JOIN n.category c
LEFT JOIN WisJaCoreBundle:Image i
WITH i.target = \'Article\' AND i.targetId = n.id AND n.movie IS NULL
LEFT JOIN WisJaCoreBundle:Comment com
WITH com.target = \'Article\' AND com.targetId = n.id
ORDER BY n.createdAt DESC
')
->setFirstResult($page * $count - $count)
->setMaxResults($count)
->getResult();
}
In table News I have a few records, but I get only one... I found problem, it's this fragment
COUNT(com.id) as numberOfComments
When I replace this for example:
n.id as numberOfComments
then all working good and I get all result. Why "COUNT" destroy my query?
EDIT------------------------------------------
I still don't know why that construction doesn't works, but problem is in same SQL, instead only "COUNT" had put nested query like this:
SELECT
n.id, n.createdAt, n.title, n.titleCanonical, n.entry, n.movie,
c.title as category,
i as images,
(SELECT COUNT(com.id) FROM WisJaCoreBundle:Comment com WHERE com.target = \'Article\' AND com.targetId = n.id) as numberOfComments
FROM WisJaCoreBundle:News n
JOIN n.category c
LEFT JOIN WisJaCoreBundle:Image i
WITH i.target = \'Article\' AND i.targetId = n.id AND n.movie IS NULL
ORDER BY n.createdAt DESC
So, problem is solved :)
I have the query below that works fine when I use it in phpMyAdmin, I am just a bit unsure how to do it within the CI framework when I have the m.id etc in place.
Query:
SELECT DISTINCT m.name, m.id, c.id, c.name
FROM `default_ps_products` p
INNER JOIN `default_ps_products_manufacturers` m ON p.manufacturer_id = m.id
INNER JOIN `default_ps_product_x_cats` x ON p.id = x.product_id
INNER JOIN `default_ps_products_categories` c ON x.category_id = c.id
There are many ways.
Example 1:
$result = $this->db
->select('m.name, m.id, c.id, c.name')
->distinct()
->join('default_ps_products_manufacturers m', 'p.manufacturer_id=m.id')
->join('default_ps_product_x_cats x', 'p.id=x.product_id')
->join('default_ps_products_categories c', 'x.category_id=c.id')
->get('default_ps_products p')
->result();
echo $this->db->last_query();
Sometimes the active record can't produce the query you want. So you can write it yourself.
Example 2:
$query = "SELECT DISTINCT m.name, m.id, c.id, c.name
FROM `default_ps_products` p
INNER JOIN `default_ps_products_manufacturers` m ON p.manufacturer_id = m.id
INNER JOIN `default_ps_product_x_cats` x ON p.id = x.product_id
INNER JOIN `default_ps_products_categories` c ON x.category_id = c.id";
$result = $this->db
->query($query)
->result();
echo $this->db->last_query();
In this second example, db::query() can take an array as the second parameter that will replace any question marks (?) within $query with the respective value. For example say you needed to add some where values to your query.
Example 3:
$query = "SELECT DISTINCT m.name, m.id, c.id, c.name
FROM `default_ps_products` p
INNER JOIN `default_ps_products_manufacturers` m ON p.manufacturer_id = m.id
INNER JOIN `default_ps_product_x_cats` x ON p.id = x.product_id
INNER JOIN `default_ps_products_categories` c ON x.category_id = c.id
WHERE c.id=?";
$result = $this->db
->query($query, array(1))
->result();
echo $this->db->last_query();
I am trying to run the following query via doctrine:
$sql = "SELECT league_id, sum(num_fans) AS total_fans FROM ("
."SELECT COUNT(*) as num_fans, t.id AS team_id, l.id AS league_id FROM fan_link fl "
."JOIN team t ON fl.team_id = t.id JOIN League l ON t.league_id = l.id GROUP BY fl.team_id"
.") a GROUP BY league_id LIMIT 0, 3";
$results = $this->em->createQuery($sql)->getScalarResult();
The query works fine in PHPMyAdmin, but when I try to run it in doctrine I get this error:
Doctrine\ORM\Query\QueryException [ 0 ]:
[Semantical Error] line 0, col 51 near '(SELECT COUNT(*)':
Error: Class '(' is not defined.
Is the parenthesis ( a reserved character in doctrine queries? I have subselects in where clauses elsewhere that work fine, but this one in the from clause doesn't want to work. What am I doing wrong?
Update:
I just tried using the query builder and got the same error. Code:
$qb = $this->em->createQueryBuilder();
$leagueQuery = $qb->select('league_id, sum(num_fans) AS total_fans')
->from("(SELECT count(*) as num_fans, t.id AS team_id, l.id AS league_id "
."FROM fan_link fl "
."JOIN team t ON fl.team_id = t.id "
."JOIN League l ON t.league_id = l.id GROUP BY fl.team_id)",
'a')
->groupBy("league_id")
->orderBy("total_fans", "DESC")
->setMaxResults(3)
->getQuery();
$results = $leagueQuery->getArrayResult();
Ended up using this:
$sql = "SELECT league_id, sum(num_fans) AS total_fans FROM "
."(SELECT COUNT(*) as num_fans, t.id AS team_id, l.id AS league_id FROM fan_link fl "
."JOIN team t ON fl.team_id = t.id JOIN League l ON t.league_id = l.id GROUP BY fl.team_id"
.") a GROUP BY league_id LIMIT 0, 3";
$q = $this->em->getConnection();
$league_results = $q->fetchAll($sql);
Spend many hours while got this working!
You could do that with createNativeQuery()
Here are working example:
$rsm = new ResultSetMapping();
$rsm->addScalarResult('c1', 'c1');
$rsm->addScalarResult('b1', 'b1');
$qb = $manager->createNativeQuery("
SELECT SUM(RESULTS.totalHours) AS c1, SUM(RESULTS.totalDuration) AS b1
FROM
(
SELECT S.totalHours, S.totalDuration
FROM S
INNER JOIN SV ON S.specificationId = SV.id
LEFT JOIN SToTagRel ST ON S.id = ST.specificationId
LEFT JOIN T ON ST.tagId = T.id
GROUP BY S.id
) AS RESULTS
", $rsm);
$qb->getSingleResult();