Doctrine Select from Subquery - php

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();

Related

Translate SQL query into codeigniter for joomla

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();

Doctrine query builder inner join with subselect

I have this query in SQL that's working fine:
SELECT tl.*
FROM table1 tl
INNER JOIN table2 tl2
ON tl.id = tl2.other_id
INNER JOIN
(
SELECT other_id, MAX(date) maxDATE
FROM table2
GROUP BY other_id
)
tlv2 ON tl2.other_id = tlv2.other_id AND
tl2.date = tlv2.maxDATE WHERE tl.access=0
ORDER BY tlv2.maxDATE DESC
Now the problem is, I cant seem to figure out how to translate this into the Doctrine query builer.
I have this:
$subquery = $this->getEntityManager()->getRepository(Table2::class)
->createQueryBuilder('tl2')
->select(array('other_id','MAX(date) maxDate'))
->groupBy('other_id')
->getDQL();
$qb = $this->createQueryBuilder('tl');
$qb->select('tl')
->innerJoin(Table2::class,'tl2','WITH','tl.id = tl2.other_id')
->innerJoin("(".$subquery.")",'tlv2','WITH','tl2.date = tlv2.maxDATE')
->where('tl.access = 0')
->orderBy('tlv2.maxDATE','DESC');
but it's giving me the error:
Subquery is not supported here
On the line where I put the $subquery variable.
I cant seem to figure out what I'm doing wrong here. What am I doing wrong?
as mentioned here if you are using the ORM then the mapping will fail, you can only run this without hydration, in case you are using the DBAL only it will work as you expect
If you would go for native query solution and still need a mapped result then you can use \Doctrine\ORM\EntityManager::createNativeQuery with \Doctrine\ORM\Query\ResultSetMapping
$sql = <<<SQL
SELECT tl.*
FROM table1 tl
INNER JOIN table2 tl2
ON tl.id = tl2.other_id
INNER JOIN
(
SELECT other_id, MAX(date) maxDATE
FROM table2
GROUP BY other_id
)
tlv2 ON tl2.other_id = tlv2.other_id AND
tl2.date = tlv2.maxDATE WHERE tl.access=0
ORDER BY tlv2.maxDATE DESC
SQL;
$rsm = new Query\ResultSetMapping();
$rsm->addEntityResult(Entity::class, 'e');
$rsm->addFieldResult('e','id', 'id');
$rsm->addFieldResult('e','date', 'createAt');
$result = $this->entityManager->createNativeQuery($sql, $rsm)->getResult();

Making query from subquery

I am trying to pass following sql query to Doctrine:
SELECT id, name, count(*) FROM (SELECT r.id, r.name, f.timestamp FROM `food_log` as f inner join recipe as r on f.recipe_id = r.id WHERE f.user_id = 6 and timestamp > "2016-09-01" and recipe_id is not null group by f.timestamp, r.id) a GROUP BY a.id ORDER BY count(*) DESC
It should return me recipes with amount of how many times particular user was using single recipe from selected timestamp.
Now I am trying to do this with Doctrine 1.2 and Symfony 1.4, however I do not know how to make query from subquery, I was trying to do something like this
$subQuery = Doctrine_Query::create()
->select('r.id, r.name, f.timestamp')
->from('FoodLog f')
->innerJoin('f.Recipe r')
->where('f.user_id = ?', $userId)
->andWhere('timestamp > ?', "2016-09-01")
->andWhere('f.recipe_id is not null')
->andWhere('r.is_premium = ?', $premium)
->groupBy('f.timestamp, r.id')
->getSqlQuery();
$query = Doctrine_Query::create()
->select('id, name, count(*)')
->from($subQuery)
->groupBy('id')
->orderBy('count(*) DESC');
return $query->fetchArray();
Anybody know where I am wrong with it ?
Thanks a lot for any response !
Basically, you can't do nested queries in this version of Doctrine. I'd recommend using a raw SQL query via the doctrine connector:
$sql = 'SELECT id, name, count(*) FROM (SELECT r.id, r.name, f.timestamp FROM `food_log` as f inner join recipe as r on f.recipe_id = r.id WHERE f.user_id = 6 and timestamp > "2016-09-01" and recipe_id is not null group by f.timestamp, r.id) a GROUP BY a.id ORDER BY count(*)
DESC';
$conn = Doctrine_Manager::getInstance()->getCurrentConnection();
$result = $conn->execute($sql);
foreach($result as $data){
// do something
}
As you're not hydrating objects, you should find this works well.

MYSQL Query to Codeigniter Query

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();

Doctrine 2 native query order by custom column

I have problem with custom ordering of result in Native Query Doctrine 2. I have this SQL tested on server:
SELECT
c.id, c.is_verified, c.email, c.phone, i.id as identityId,
i.firstname, i.lastname, g.id as groupId, g.name as groupName,
r.id as roleId, r.name as roleName
FROM
UserCredential c
JOIN
UserIdentity i
ON
i.id = c.identity_id
JOIN
Role r
ON
r.id = c.role_id
LEFT JOIN
`Group` g
ON
g.id = c.group_id
ORDER BY
i.firstname ASC
LIMIT
10
OFFSET
0
Everything works but, when I rewrote this to Native Query in Custom repository:
$query = $this->_em->createNativeQuery('
SELECT
c.id,
c.is_verified,
c.email,
c.phone,
i.id as identityId,
i.firstname,
i.lastname,
g.id as groupId,
g.name as groupName,
r.id as roleId,
r.name as roleName
FROM
UserCredential c
JOIN
UserIdentity i
ON
i.id = c.identity_id
JOIN
Role r
ON
r.id = c.role_id
LEFT JOIN
`Group` g
ON
g.id = c.group_id
ORDER BY
:orderBy
LIMIT
:lmt
OFFSET
:ofs
', $rsm);
$query->setParameter('orderBy', implode(', ', $orderBy));
$query->setParameter('lmt', $limit);
$query->setParameter('ofs', $offset);
Where $orderBy is array $column => $orderType.
But if I change order by parameters result from this query is always returned with default ordering (c.id ASC).
I've tested this and query is generated OK but I don't know why is result always ordered by default. Is Doctrine 2 somehow ignoring ORDER BY?

Categories