I'm using Doctrine ORM with PHP and with MariaDB. I'm trying to fetch only the paid orders from the database. Here's my code:
public function listOrders($filter = [], $limit = 50, $offset = 0): array {
$qb = $this->entityManager->createQueryBuilder();
$page = isset( $filter['page'] ) ? $filter['page'] - 1 : $offset;
$perPage = $filter['perPage'] ?? $limit;
$firstResult = $page * $perPage;
$orderBy = isset($filter['sortBy'])
? 'orders.'.$filter['sortBy']
: 'orders.created';
$qb
->select('orders')
->from(OrderData::class, 'orders')
->setFirstResult($firstResult)
->setMaxResults($perPage)
->orderBy($orderBy, isset($filter['sortDesc']) ? 'ASC' : 'DESC ');
// Filter by orders that are paid
if (isset($filter['paid']) && $filter['paid']) {
$qb
->leftJoin('orders.items', 'item')
->addSelect('SUM(item.price) AS item_prices')
->leftJoin('orders.transactions', 'transaction')
->addSelect('SUM(transaction.price) AS paid_amount')
->andWhere(
$qb->expr()->eq(
'paid_amount',
'item_prices'
) // Get only paid orders
);
}
...
}
The error I'm getting:
An exception occurred while executing
SELECT
DISTINCT id_0
FROM
(
SELECT
DISTINCT id_0,
created_2
FROM
(
SELECT
o0_.id AS id_0,
o0_.token AS token_1,
o0_.created AS created_2,
o0_.updated AS updated_3,
o0_.requestId AS requestId_4,
SUM(o1_.price) AS sclr_5,
SUM(o2_.price) AS sclr_6,
o1_.price AS price_7,
o2_.price AS price_8,
o1_.type AS type_9
FROM
orders o0_
LEFT JOIN orders_items o1_ ON o0_.id = o1_.order_id
LEFT JOIN orders_items_journeys o3_ ON o1_.id = o3_.id
LEFT JOIN orders_items_railpasses o4_ ON o1_.id = o4_.id
LEFT JOIN orders_items_articles o5_ ON o1_.id = o5_.id
LEFT JOIN orders_items_distributions o6_ ON o1_.id = o6_.id
LEFT JOIN orders_items_giftcard o7_ ON o1_.id = o7_.id
LEFT JOIN orders_transactions o2_ ON o0_.id = o2_.order_id
WHERE
sclr_6 = sclr_5
ORDER BY
o2_.created DESC
) dctrn_result_inner
ORDER BY
created_2 DESC
) dctrn_result
LIMIT
30
':SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sclr_6' in 'where clause'
The syntax is valid, but it can not recognize the generated column for some reason.
Any help would be appreciated.
Related
Hello i am trying to rewrite ZF query builder into doctrine ORM.
Here IS mine old Zend framework query.
$dependent = new Zend_Db_Expr('if(br.billing_rate = \'dependent\',(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id),0)');
$select = $this
->select()->setIntegrityCheck(false)
->from(array('brg' => 'childcare_billing_rule_group'), array())
->joinInner(array('br' => 'childcare_billing_rule'), 'br.id = brg.billing_rule_id', array('*', 'dependent' => $dependent))
->join(array('brp' => 'childcare_billing_rule_price'), 'br.id = brp.childcare_billing_rule_id', array('age_from', 'age_to', 'default_rate' => 'rate'))
->where('is_default != 1')
->where('br.billing_type in (\'' . implode('\',\'', array(self::BILLING_TYPE_PER_DAY, self::BILLING_TYPE_PER_HOUR, self::BILLING_TYPE_PER_UNLIMITED, self::BILLING_TYPE_PER_RESERVATION)) . '\')')
->where('brg.group_id IN (?)', $groupId)
->group('brp.id')
->having('dependent <= ?', $dependentLevel)
->order('dependent desc')
->order('brp.rate');
And here it is SQL row value
SELECT `br`.*,
if (br.billing_rate = 'dependent',
(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id),
0) AS `dependent`,
`brp`.`age_from`,
`brp`.`age_to`,
`brp`.`rate` AS `default_rate`
FROM `childcare_billing_rule_group` AS `brg`
INNER JOIN `childcare_billing_rule` AS `br` ON br.id = brg.billing_rule_id
INNER JOIN `childcare_billing_rule_price` AS `brp` ON br.id = brp.childcare_billing_rule_id
WHERE (is_default != 1)
AND (br.billing_type in ('Per Day','Per Hour','Unlimited','Per Reservation'))
AND (brg.group_id IN (103))
AND ((brp.age_from = 0 AND brp.age_to = 0) || 3.1666666666667
BETWEEN brp.age_from AND brp.age_to)
GROUP BY `brp`.`id` HAVING (dependent <= '0')
ORDER BY `dependentw` desc,
`brp`.`rate` ASC
I am not sure how to implement this sub query
new Zend_Db_Expr('if(br.billing_rate = \'dependent\',(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id),0)');
My code so far
$subQuery = $subQueryBuilder
->select('if (br.billing_rate = 'dependent',
(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id)')
->getSQL();
$queryBuilder->select($alias)
->addSelect($subQuery)
->innerJoin(ChildcareBillingRule::class, 'br', Join::WITH, 'br.id = childcare_billing_rule_group.childcareBillingRule')
->innerJoin(ChildcareBillingRulePrice::class, 'brp', Join::WITH, 'br.id = brp.childcareBillingRule')
->where("br.billingType in (:billingTypes)")
->andWhere( 'br.isDefault != :isDefault')
->andWhere( 'childcare_billing_rule_group.groupId in (:groupId)')
->setParameter('groupId', [103])
->setParameter('isDefault', 1)
->setParameter('billingTypes', ['Per Hour', 'Per Reservation', 'Per Day', 'Unlimited'])
->having('dependent <= ?', $dependentLevel')
->groupBy('brp.id')
->orderBy('brp.rate') ;
->getQuery()->getSingleResult();
so i am trying to add sub query with addSelect but not sure is this the right way? Any Help or idea is appreciated? Tnx
in short instead of ->getSQL() you should use ->getDQL().
Yours code will be like:
$dql = $this->createQueryBuilder()
->select('count(id)')
->from({Class::FQDN}, {ALIAS})
->getDQL();
$result = $this->createQueryBuilder()
->select({SECOND_ALIAS})
->from({SecondClass::FQDN}, {SECOND_ALIAS})
->where((new \Expr())->gt('{SECOND_ALIAS}.cnt', $dql))
->getQuery()
->getResult();
This is a search function that returns each member with their most recent year registered.
I got it working with a DB::raw() call. But can't get it working with the query builder.
Working Code:
$query = DB::table('membership as m');
$query->join(
DB::raw(
'(SELECT my.*
FROM membership_years my
INNER JOIN (
SELECT member_id,MAX(membership_year) AS max_my
FROM membership_years
GROUP BY member_id
) my2
ON my.member_id = my2.member_id
AND my.membership_year = my2.max_my
) my'
)
,'m.id','=','my.member_id');
My attempt on query builder code:
$query = DB::table('membership as m');
$query->join('membership_years as my',
function($j1){
$j1->join('membership_years as my2',
function($j2){
$j2->where('my.membership_year','=','MAX(my2.membership_year)')
->on('my.member_id','=','my2.member_id');
}
)->on('m.id','=','my.member_id');
}
);
The resulting error is:
Call to undefined method Illuminate\Database\Query\JoinClause::join()
I'm not sure if this is because the $j2 doesn't have access to the join method anymore?
Raw MySQL query:
SELECT my.membership_year,m.*
FROM membership AS m
INNER JOIN
(
SELECT my1.*
FROM membership_years my1
INNER JOIN
(
SELECT member_id,MAX(membership_year) AS max_my
FROM membership_years
GROUP BY member_id
) my2
ON my1.member_id = my2.member_id
AND my1.membership_year = my2.max_my
) my
ON m.id = my.member_id
ORDER BY m.id ASC
Way 1. You can write part of the query with builder:
$query = DB::table('membership as m')
->select('my.membership_year', 'm.*')
->join(DB::raw('(
SELECT my1.*
FROM membership_years my1
INNER JOIN (
SELECT member_id, MAX(membership_year) AS max_my
FROM membership_years
GROUP BY member_id
) my2
ON my1.member_id = my2.member_id
AND my1.membership_year = my2.max_my
) my'),
'm.id', '=', 'my.member_id')
->orderBy('m.id');
Way 2. Also you can write subqueries and use toSql() method:
$sub1 = DB::table('membership_years')
->select('member_id', DB::raw('MAX(membership_year) AS max_my'))
->groupBy('member_id');
$sub2 = DB::table('membership_years as my1')
->select('my1.*')
->join(DB::raw('(' . $sub1->toSql() . ') my2'),
function ($join) {
$join
->on('my1.member_id', '=', 'my2.member_id')
->on('my1.membership_year', '=', 'my2.max_my');
});
$query = DB::table('membership as m')
->select('my.membership_year', 'm.*')
->join(DB::raw('(' . $sub2->toSql() . ') my'), 'm.id', '=', 'my.member_id')
->orderBy('m.id');
Inner join in my doctrine2 query increases execution time from 400 milliseconds to 5 secs, but if I extract SQL and run directly in SQLSERVER studio it takes few milliseconds to execute.
below is my query, the bottle neck is inner join only:
$qb = $em->createQueryBuilder();
$q = $qb->select( 'wp.id, wp.last_activity_datetime' )
->from( '\Entities\wall_post', 'wp' )
->LeftJoin( 'wp.wall_postsLikes', 'likes' )
->LeftJoin( 'wp.wall_postsShare', 'shares' )
->LeftJoin( 'wp.wall_postsComment', 'comments' )
->leftJoin( 'wp.wall_postsFrom_user','fromUser');
if( $wall_type == self::WALL_TYPE_SOCIALISE )
{
$q->leftJoin( 'wp.wall_postsSocialise_album','album');
$q->innerJoin( 'album.socialise_albumsSocialise_photo','photo');
}
$q->setParameter( 'my_links_r', $my_links_r )
->setParameter( 1, $userId )
->setFirstResult( $offset )
->setMaxResults( $limit )
->groupBy( 'wp.id, wp.last_activity_datetime' )
->orderBy( 'wp.last_activity_datetime', 'DESC' );
if( $wall_type )
{
$q->where( 'wp.wall_postsFrom_user = ?1 AND wp.wall_type = ?4' );
$q->orWhere( 'wp.wall_postsFrom_user IN (:my_links_r) AND wp.wall_type = ?4' );
$q->orWhere( 'likes.likesLiked_by IN (:my_links_r) AND wp.wall_type = ?4' );
$q->orWhere( 'shares.sharesShared_by IN (:my_links_r) AND wp.wall_type = ?4' );
$q->orWhere( 'comments.commentsIlook_user IN (:my_links_r) AND wp.wall_type = ?4' );
$q->andWhere('fromUser.account_closed_on is null');
if( $blocked_user_ids_arr ):
$q->setParameter( 'blocked_users_r', $blocked_user_ids_arr );
$q->andWhere( 'wp.wall_postsFrom_user NOT IN (:blocked_users_r)' );
endif;
$q->setParameter( 4, $wall_type );
}
$q = $q->getQuery()->getResult( \Doctrine\ORM\Query::HYDRATE_ARRAY );
Following is my SQL extract, it runs fantastic with inner join also:
SELECT TOP 10 w0_.id AS id0, w0_.last_activity_datetime AS last_activity_datetime1
FROM wall_post w0_
LEFT JOIN likes l1_ ON w0_.id = l1_.wall_post_id
LEFT JOIN share s2_ ON w0_.id = s2_.wall_post_id
LEFT JOIN comments c3_ ON w0_.id = c3_.wall_post_id
LEFT JOIN ilook_user i4_ ON w0_.from_user_id = i4_.id
LEFT JOIN socialise_album s5_ ON w0_.socialise_album_id = s5_.id
INNER JOIN socialise_photo s6_ ON s5_.id = s6_.socialise_album_id
WHERE ((w0_.from_user_id = 1 AND w0_.wall_type = 2)
OR (w0_.from_user_id IN (1) AND w0_.wall_type = 2)
OR (s2_.ilook_user_id IN (1) AND w0_.wall_type = 2))
AND i4_.account_closed_on IS NULL
GROUP BY w0_.id, w0_.last_activity_datetime
ORDER BY w0_.last_activity_datetime DESC
Any help would be appreciated.
It is not exact answer but solves my purpose if I use having statement and left join in stead of inner join:
$q->leftJoin( 'album.socialise_albumsSocialise_photo','photo');
$q->having('count(photo) > 1');
I'm trying to use a result of subquery in where clause , but I failed
I'm using a laravel db class
this is my code
DB::table('sales as SL')
->join('prsn as PR1','PR1.id_person','=','SL.customer_id')
->join('prsn as PR2','PR2.id_person','=','SL.investor_id')
->select('SL.customer_id' ,'SL.investor_id','SL.type_agd','SL.status','SL.id_agd','PR1.full_name_person as Buyer'
,'PR2.full_name_person as Seller','PR1.mobile1_person as Mobile',
DB::raw('(select SUM(money_operation) from opers where agd_operation = SL.id_agd AND ty IN ("3","4","5","6","7","8","9","10","12") AND status = 1 ) as Madfoo3'),
DB::raw('(select SUM(money) from inst where agd_id = SL.id_agd AND date <= "'.DT::Today('Ymd').'" AND type != "D") as Matloob'),
DB::raw('(select (Matloob - Madfoo3 )) Mutakher' ))
->whereRaw('(Mutakher > 0)')
->paginate();
this error appear:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Mutakher' in 'where clause' (SQL: select count(*) as aggregate from `sales` as `SL` inner join `prsn` as `PR1` on `PR1`.`id_person` = `SL`.`customer_id` inner join `prsn` as `PR2` on `PR2`.`id_person` = `SL`.`investor_id` where (Mutakher > 0))
/var/www/Taqseet/vendor/laravel/framework/src/Illuminate/Database/Connection.php#625
I want to make a condition if the "Mutakher" > 0 give me the raw.
Thanks
I solve this problem
DB::table('sales as SL')
->join('prsn as PR1','PR1.id_person','=','SL.customer_id')
->join('prsn as PR2','PR2.id_person','=','SL.investor_id')
->select('SL.customer_id' ,'SL.investor_id','SL.type_agd','SL.status','SL.id_agd','PR1.full_name_person as Buyer'
,'PR2.full_name_person as Seller','PR1.mobile1_person as Mobile',
DB::raw('(select SUM(money_operation) from opers where agd_operation = SL.id_agd AND ty IN ("3","4","5","6","7","8","9","10","12") AND status = 1 ) as Madfoo3'),
DB::raw('(select SUM(money) from inst where agd_id = SL.id_agd AND date <= "'.DT::Today('Ymd').'" AND type != "D") as Matloob'),
DB::raw('(select (Matloob - Madfoo3 )) Mutakher' ))
->whereRaw('((Matloob - Madfoo3 ) > 0)')
->paginate();
So i have this raw SQL that i want to call via the zend framework
select t.type, t.tid,t.tname,t.cid,t.cname, ls.*
from
(
select t.type, t.id as tid, t.name as tname, c.id as cid, c.name as cname from team t
join company c on t.parent=c.id and t.type='C' and c.sector=20 and t.status='ACTIVE'
union
select t.type, t.id as tid,t.name as tname, null as cid, null as cname from team t
join sector s on t.parent=s.id and t.type='S'and s.id=20 and t.status='ACTIVE'
) t
LEFT JOIN leaguesummary ls ON ls.leagueparticipantid=t.tid AND ls.leaguetype='T'
WHERE ls.leagueid = 5
ORDER BY ls.leaguedivision asc, ls.leagueposition asc LIMIT 10;
I have my model class which extends Zend_Db_Table i've a simple method to build the SQL and query it
class Model_DbTable_LeagueSummary extends Zend_Db_Table_Abstract {
....
public function getTeamLeagueSummayBySector($sectorid,$limit=10)
{
$select = $this->select()
->setIntegrityCheck(false)
->from(array('team'=>'team'),array('type','id','name'))
->join(array('company'=>'company'),'team.parent=company.id',array())
->where('team.type="C"')
->where('team.status="ACTIVE"')
->where('company.sector=?',$sectorid);
$select2 = $this->select()
->setIntegrityCheck(false)
->from(array('team'=>'team'),array('type','id','name'))
->join(array('sector'=>'sector'),'team.parent=sector.id',array())
->where('team.type="S"')
->where('team.status="ACTIVE"')
->where('sector.id=?',$sectorid);
// manually creating the SQL string and calling Zend_Db_Table::getDefaultAdapter() directly
$STRING = sprintf("select x.*,ls.* from ( %s union %s ) x
LEFT JOIN leaguesummary ls ON ls.leagueparticipantid=x.id AND ls.leaguetype='T'
WHERE ls.leagueid = 5
ORDER BY ls.leaguedivision asc, ls.leagueposition asc LIMIT 10;",$select,$select2);
$db = Zend_Db_Table::getDefaultAdapter();
$stmt = $db->query($STRING);
$stmt->setFetchMode(Zend_Db::FETCH_OBJ);
$result = $stmt->fetchAll();
return $result;
}
This query works, but don't like the solution and wanted to refactor the code to use the Zend_DB methods more correctly. I've gotten this far
$sql = $this->select()
->setIntegrityCheck(false)
->from(array('X'=>'X'))
->union(array($select,$select2))
->joinLeft(array('leaguesummary'=>'leaguesummary'),'leaguesummary.leagueparticipantid=X.id')
->where('leaguesummary.leaguetype="T"')
->where("leaguesummary.leagueid = ?",5)
->order("leaguesummary.leaguedivision asc")
->order("leaguesummary.leagueposition asc")
->limit($limit);
return $db->fetchAll($sql);
But i get this exception. Whats wrong with the union statements?
Message: Invalid use of table with UNION
Stack trace:
#0 /home/assure/bhaa/zend/trunk/library/Zend/Db/Select.php(357): Zend_Db_Select->_join('left join', Array, 'leaguesummary.l...', '*', NULL)
#1 /home/assure/bhaa/zend/trunk/application/models/DbTable/LeagueSummary.php(175): Zend_Db_Select->joinLeft(Array, 'leaguesummary.l...')
#2 /home/assure/bhaa/zend/trunk/application/controllers/HousesController.php(110): Model_DbTable_LeagueSummary->getTeamLeagueSummayBySector('20')
#3 /home/assure/bhaa/zend/trunk/library/Zend/Controller/Action.php(513): HousesController->sectorAction()
#4 /home/assure/bhaa/zend/trunk/library/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch('sectorAction')
#5 /home/assure/bhaa/zend/trunk/library/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#6 /home/assure/bhaa/zend/trunk/library/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
#7 /home/assure/bhaa/zend/trunk/library/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
-- EDIT 2 --
So i added a third step and merge the two union sql statements like this
$union = $this->getDefaultAdapter()->select()->union(array($select,$select2));
$logger->info(sprintf(' (%s) ',$union));
which gives me valid SQL
2010-06-04T15:11:55+00:00 INFO (6): (SELECT `team`.`type`, `team`.`id`, `team`.`name` FROM `team` INNER JOIN `company` ON team.parent=company.id WHERE (team.type="C") AND (team.status="ACTIVE") AND (company.sector='20') UNION SELECT `team`.`type`, `team`.`id`, `team`.`name` FROM `team` INNER JOIN `sector` ON team.parent=sector.id WHERE (team.type="S") AND (team.status="ACTIVE") AND (sector.id='20'))
The next step was to integrate this union clause into the main query, I've played around with the from() clause like so
->from(array('X'=> '('.$union.')' ) )
->joinLeft(array('leaguesummary'=>'leaguesummary'),'leaguesummary.leagueparticipantid=X.id')
->where('leaguesummary.leaguetype="T"')
->where("leaguesummary.leagueid = ?",5)
->order("leaguesummary.leaguedivision asc")
->order("leaguesummary.leagueposition asc")
->limit($limit);
$logger->info(sprintf('%s',$sql));
return $this->getDefaultAdapter()->fetchAll($sql);
but it seems that when the '$union' variable to converted to a string it is somehow getting shortened, which means my SQL is invalid
SELECT `X`.*, `leaguesummary`.* FROM `(SELECT ``team```.```type``, ``team``` AS `X` LEFT JOIN `leaguesummary` ON leaguesummary.leagueparticipantid=X.id WHERE (leaguesummary.leaguetype="T") AND (leaguesummary.leagueid = 5) ORDER BY `leaguesummary`.`leaguedivision` asc, `leaguesummary`.`leagueposition` asc LIMIT 10
Any ideas?
For a query as "complicated" as yours, you may not want to do it the "Zend" way. You can use the query() function with raw SQL
$rows = $this->getAdapter()->query("
select t.type, t.tid,t.tname,t.cid,t.cname, ls.*
from
(
select t.type, t.id as tid, t.name as tname, c.id as cid, c.name as cname from team t
join company c on t.parent=c.id and t.type='C' and c.sector=20 and t.status='ACTIVE'
union
select t.type, t.id as tid,t.name as tname, null as cid, null as cname from team t
join sector s on t.parent=s.id and t.type='S'and s.id=20 and t.status='ACTIVE'
) t
LEFT JOIN leaguesummary ls ON ls.leagueparticipantid=t.tid AND ls.leaguetype='T'
WHERE ls.leagueid = 5
ORDER BY ls.leaguedivision asc, ls.leagueposition asc LIMIT 10;
");
This bug report shows the proper use for the union() function:
$selectA = $db->select()
->from(array('u' => 'user'), 'name')
->where('u.id >= 5');
$selectB = $db->select()
->from(array('u' => 'user'), 'name')
->where('u.id < 5');
$select = $db->select()
->union(array($selectA, $selectB));
Or alternatively:
$select = $db->select()
->union(array(
$db->select()
->from(array('u' => 'user'), 'name')
->where('u.id >= 5'),
$db->select()
->from(array('u' => 'user'), 'name')
->where('u.id < 5')
));
$pmSort = 'user_lname DESC';
$qry1=$this->select()
->setIntegrityCheck(false)
->from(array('team'=>'plg_team'),array('team_id','team_name','team_sprt_id','team_user_id'))
->joinInner(array('user'=>'plg_users'),'user.user_id=team_user_id',array('user_fname','user_lname','user_email'))
->where("team_id='$pmTeamID' and team_status=1 and user_status=1");
$qry2=$this->select()
->setIntegrityCheck(false)
->from(array('t'=>'plg_team'),array('team_id'))
->joinInner(array('tp'=>'plg_team_players'),'t.team_id = tp.plyr_team_id',array('plyr_id'))
->joinInner(array('rlsp'=>'plg_relationships'),'rlsp.rlsp_rsty_id = 2',array('rlsp_id'))
->joinInner(array('user'=>'plg_users'),'user.user_id = rlsp.rlsp_relation_user_id',array('user_id','user_fname','user_lname','user_email'))
->where("user.user_status=1 and t.team_status=1 and tp.plyr_status=1 and t.team_id='$pmTeamID' and rlsp.rlsp_user_id = tp.plyr_user_id");
$select = $this->select()
->setIntegrityCheck(false)
->union(array($qry1, $qry2));
$select1 = $this->select()
->setIntegrityCheck(false)
->from(array('T'=> $select ) )
->order($pmSort);
echo $select1;