Making query from subquery - php

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.

Related

Laravel Eloquent DB::Raw query does not allow WHERE statement and subquery together

The following query runs just fine when I paste it into my SQL tool, but through Laravel, it returns zero rows.
$sql = "
SELECT main_query.* FROM (
SELECT
c.id,
c.name,
c.order,
cd.case,
(SELECT count(*) from logs cl
where
c.id = cl.id
and cl.status = 'OPEN'
) as cl_count,
sdsc.task
FROM `table` c
INNER JOIN `table2` cd ON (c.id = cd.id)
LEFT JOIN `table3` sdsc ON (c.id = sdsc.id)
WHERE
c.status = 'NEW'
GROUP BY c.id
ORDER BY cd.updated_at DESC
) main_query
where main_query.cl_count > 1
GROUP BY main_query.id
ORDER BY main_query.updated_at DESC
limit 0,20
";
Due to the complexity of the actual query, I cannot convert it wholly into an eloquent query, so I am executing it using DB::select(DB::raw($searchQuery));
If I remove where main_query.cl_count > 1, the query runs just fine. What is causing this to fail, and how do I rewrite the code?
Try below code, generated by https://sql2builder.github.io/
DB::query()->fromSub(function ($query) {
$query->from('table')
->select('table.id', 'table.name', 'table.order', 'table2.case', 'table3.task')
->on(function ($query) {
$query->where('table.id','=','table2.id');
})
->on(function ($query) {
$query->where('table.id','=','table3.id');
})
->where('table.status','=','NEW')
->groupBy('table.id')
->orderBy('','desc');
},'main_query')
->select('main_query.*')
->where('main_query.cl_count','>',1)
->groupBy('main_query.id')
->orderBy('','desc')
->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();

Cannot use mysql function IN in laravel db statement

Im having a problem when using the IN function of MySQL in a Laravel 5.2 DB Statement. Here is the example:
$str_array = implode(",",$array_reservations);
$sql_result = DB::select("
select r.id,r.people,r.date,r.status,p.alias,u.name,p.profile
from reservations r inner join places p on p.id = r.place_id
inner join users u on u.id = r.user_id
where r.id in(?)
order by r.date desc
", [$str_array]);
But in the result I just get the result of the first reservation of the array.
The length of the array will be always variable.
In this case you need to use DB::raw. Also, you need to create as many "?" you need, for each id you want to bind. That's the way PDO works:
$str_array = implode(",",$array_reservations);
$bindings = trim(str_repeat('?,', count($array_reservations)), ',');
DB::select($sql, $inputids);
$sql_result = DB::select(DB::raw("
select r.id,r.people,r.date,r.status,p.alias,u.name,p.profile
from reservations r inner join places p on p.id = r.place_id
inner join users u on u.id = r.user_id
where r.id in($bindings)
order by r.date desc
"), $str_array);
But, IMO, you should use Query Builder:
DB::table('reservations')
->join('places','places.id','=','reservarions.place_id')
->join('users','users.id','=','reservarions.user__id')
->whereIn('reservations.id',$str_array)
->orderBy('reservations.date', 'DESC');
Try this :
$sql_result = DB::table('reservations AS r')
->join('places AS p', 'p.id', '=', 'r.place_id')
->join('users AS u', 'u.id', '=', 'r.user_id')
->select('r.id','r.people','r.date','r.status','p.alias','u.name','p.profile')
->whereIn('r.id',$str_array) // write you conditions in array
->orderBy('r.date', 'desc')
->get();

Doctrine Select from Subquery

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

SQL Join fetching same name row

I've got 2 tables, a join, a SELECT *. Both tables contain the field id, but I need to explicitly access one in this way:
$query = "SELECT * FROM #__docman as d JOIN #__users u ON d.dmmantainedby = u.id WHERE d.catid = 5 ORDER BY d.id ASC";
$db->setQuery($query);
$rows = $db->loadObjectList();
foreach($rows as $row) {
echo $row->id ;
}
I tried
echo $row->d.id;
That didn't work..I know I could technically change my SELECT to call for the id's and use aliases but, there are a lot of fields I am fetching, hence the *. Is there another way?
You'll have to use aliases, the query stays short if you duplicate the data:
"SELECT *, d.id as did, u.id as uid FROM #__docman as d JOIN #__users u ON d.dmmantainedby = u.id WHERE d.catid = 5 ORDER BY d.id ASC"
And then:
$row->did
$row->uid
SELECT *, d.id AS id_alias FROM ... ? This will select duplicate columns but will still be pretty short query.

Categories