Doctrine: GROUP BY HAVING - doctrine

I'm trying to do this:
SELECT
userId, count(userId) as counter
FROM
quicklink
GROUP BY
userId
HAVING
count(*) >= 3'
In doctrine with the querybuilder, I've got this:
$query = $this->createQueryBuilder('q')
->select('userId, count(userId) as counter')
->groupby('userId')
->having('counter >= 3')
->getQuery();
return $query->getResult();
Which gives me this error:
[Semantical Error] line 0, col 103 near 'HAVING count(*)': Error: Cannot group by undefined identification variable.
Really struggling with doctrine. :(

Your SQL is valid, Your query builder statement is invalid
All cause db will execute that query in following order:
1. FROM $query = $this->createQueryBuilder('q')
2. GROUP BY ->groupby('userId') // GROUP BY
3. HAVING ->having('counter >= 3')
4. SELECT ->select('userId, count(userId) as counter')
So as You can see counter is defined after its use in having.
Its SQL Quirk. You can not use definitions from select in where or having statements.
So correct code:
$query = $this->createQueryBuilder('q')
->select('userId, count(userId) as counter')
->groupby('userId')
->having('count(userId) >= 3')
->getQuery();
return $query->getResult();
Do note repetition in having from select

I am going to answer for people who still have this type of error.
First things first, you seem to have translated a native sql query inside a query builder object. More so, you have named your object as q
$query = $this->createQueryBuilder('q');
What this means, in general, is that every condition or grouping etc you have in your logic should address fields of q: q.userId, q.gender, ...
So, if you had written your code like below, you would have avoided your error:
$query = $this->createQueryBuilder('q')
->select('q.userId, count(q.userId) as counter')
->groupby('q.userId')
->having('counter >= 3')
->getQuery();
return $query->getResult();

I think you are missing the 'from' statement

$query = "t, count(t.userId) as counter FROM YourBundle:Table t group by t.userId having counter >1 ";
return $this->getEntityManager()->createQuery($query)->getResult();
This should work. You can even do left joins or apply where clausules.

you can define HAVING parameter via setParameter() method as well
$qb->groupBy('userId');
$qb->having('COUNT(*) = :some_count');
$qb->setParameter('some_count', 3);

Related

Argument 1 passed to Illuminate\Database\Grammar::parameterize() must be of the type array, object given

I am using Laravel 5.5 and I have translated the following query:
'SELECT *
FROM instruments
LEFT join financials on instruments.id=financials.instruments_id
WHERE financials.id IN
( SELECT MAX(financials.id)
FROM financials
GROUP BY financials.instruments_id )
ORDER BY instruments.id ASC'
into eloquent:
$overviewArray = DB::table('instruments')
->leftJoin('financials', 'instruments.id', '=', 'financials.instruments_id')
->whereIn('financials.id', DB::raw('SELECT MAX(financials.id)
FROM financials
GROUP BY financials.instruments_id )
ORDER BY instruments.id ASC'))->get()->toArray();
However, I get the following error:
In Grammar.php line 135:
Type error: Argument 1 passed to Illuminate\Database\Grammar::parameterize() must be of the type array, object given, called
in C:\Users\admin\Desktop\Coding Projects\laravel_project\vendor\laravel\framework\src\Illuminate\Database\Query\Gramm
ars\Grammar.php on line 250
My guess is that my eloquent query is wrong? Any suggestions what is wrong with it?
I appreciate your replies!
$overviewArray = DB::table('instruments')
->leftJoin('financials', 'instruments.id', '=', inancials.instruments_id')
->whereIn('financials.id', function($query){
$query->select(DB::raw('MAX(financials.id)'))->
from('financials')->
groupBy('financials.instruments_id');})
->orderBy('instruments.id')
->get()
->toArray();
I guess it will be ok.
In my case it was because I was doing Event::get(44) instead of Event::find(44).

SEQUEL - Subquery count syntax

Can anyone help me with the sequel syntax for the following the ruby orm sequel:
SELECT *, (SELECT COUNT(*) FROM todos WHERE reference_email_id = "emails".id) todo_count
FROM "emails"
INNER JOIN "email_participants"
ON ("email_participants"."email_id" = "emails"."id")
WHERE ("user_id" = 1)
I cannot quite get the syntax, I have this so far:
scope = Email.inner_join(:email_participants, {email_id: :id})
.where(user_id: query.user_id)
.select_append {
Attachment.where(reference_email_id: Sequel.qualify(:emails, :id))
.count(:id)
.exists
.as(:attachment_count)
}
I get the following error:
missing FROM-clause entry for table "emails" LINE 1: ... FROM
"attachments" WHERE ("reference_email_id" = "emails"."...
My guess is you should remove the .exists line. It's hard to say conclusively since you didn't post the SQL produced.

writing the query in codeigniter giving a different result than required

I am working on codeigniter and I am writing the following query:
$this->db->select('*');
$this->db->from('tbl_profile');
$this->db->join('tbl_msg', 'tbl_msg.msg_sender_id = tbl_profile.profile_id');
$this->db->order_by("msg_id", "desc");
$query = $this->db->get('', $config['per_page'], $this->uri->segment(3));
$data['records'] = $query->result_array();
Correspondingly I am getting the following result:
SELECT (*) FROM tbl_profile
JOIN tbl_msg ON tbl_msg.msg_sender_id = tbl_profile.profile_id
Which is returninng a wrong result as I want the result corresponding to the following query:
select * from tbl_profile as A
join (select * from tbl_msg) as B on A.profile_id = B.msg_sender_id
Please help
First of all, you missing the order by clause, but I assum, you mean other differences.
If you want that, you can use this query, what will gave you back the exact code:
$this->db->select('*', FALSE);
$this->db->from('tbl_profile as A');
$this->db->join('( select * from tbl_msg ) as B', 'A.msg_sender_id = B.profile_id');
$this->db->order_by("msg_id", "desc");
$query = $this->db->get('', $config['per_page'], $this->uri->segment(3));
$data['records'] = $query->result_array();
From codeigniter user manual:
$this->db->select()
accepts an optional second parameter. If you set it to FALSE, CodeIgniter will not try to protect your field or table names with backticks. This is useful if you need a compound select statement.

Symfony2 subquery within Doctrine entity manager

I need to perform this query:
SELECT * FROM (SELECT * FROM product WHERE car = 'large' ORDER BY onSale DESC) AS product_ordered GROUP BY type
In Symfony2 using the entity manager.
My basic query builder would be :
$query = $em->getRepository('AutomotiveBundle:Car')
->createQueryBuilder('p')
->where('pr.car = ?1')
->andWhere('pr.status = 1')
->orderBy('pr.onSale', 'DESC')
->setParameter(1, $product->getName())
->groupBy('p.type')
->getQuery();
But I cannot work out how to add in a subquery to this.
Ive tried making a separate query and joining it like:
->andWhere($query->expr()->in('pr.car = ?1',$query2->getQuery()));
But I get:
Call to undefined method Doctrine\ORM\Query::expr()
One trick is to build two queries and then use getDQL() to feed the first query into the second query.
For example, this query returns a distinct list of game ids:
$qbGameId = $em->createQueryBuilder();
$qbGameId->addSelect('distinct gameGameId.id');
$qbGameId->from('ZaysoCoreBundle:Event','gameGameId');
$qbGameId->leftJoin('gameGameId.teams','gameTeamGameId');
if ($date1) $qbGameId->andWhere($qbGameId->expr()->gte('gameGameId.date',$date1));
if ($date2) $qbGameId->andWhere($qbGameId->expr()->lte('gameGameId.date',$date2));
Now use the dql to get additional information about the games themselves:
$qbGames = $em->createQueryBuilder();
$qbGames->addSelect('game');
$qbGames->addSelect('gameTeam');
$qbGames->addSelect('team');
$qbGames->addSelect('field');
$qbGames->addSelect('gamePerson');
$qbGames->addSelect('person');
$qbGames->from('ZaysoCoreBundle:Event','game');
$qbGames->leftJoin('game.teams', 'gameTeam');
$qbGames->leftJoin('game.persons', 'gamePerson');
$qbGames->leftJoin('game.field', 'field');
$qbGames->leftJoin('gameTeam.team', 'team');
$qbGames->leftJoin('gamePerson.person', 'person');
// Here is where we feed in the dql
$qbGames->andWhere($qbGames->expr()->in('game.id',$qbGameId->getDQL()));
Kind of a long example but i didn't want to edit out stuff and maybe break it.
You can use DBAL for performing any sql query.
$conn = $this->get('database_connection');//create a connection with your DB
$sql="SELECT * FROM (SELECT * FROM product WHERE car =? ORDER BY onSale DESC) AS product_ordered GROUP BY type"; //Your sql Query
$stmt = $conn->prepare($sql); // Prepare your sql
$stmt->bindValue(1, 'large'); // bind your values ,if you have to bind another value, you need to write $stmt->bindValue(2, 'anothervalue'); but your order is important so on..
$stmt->execute(); //execute your sql
$result=$stmt->fetchAll(); // fetch your result
happy coding

How to order by count in Doctrine 2?

I'm trying to group my entity by a field (year) and do a count of it.
Code:
public function countYear()
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('b.year, COUNT(b.id)')
->from('\My\Entity\Album', 'b')
->where('b.year IS NOT NULL')
->addOrderBy('sclr1', 'DESC')
->addGroupBy('b.year');
$query = $qb->getQuery();
die($query->getSQL());
$result = $query->execute();
//die(print_r($result));
return $result;
}
I can't seem to say COUNT(b.id) AS count as it gives an error, and
I do not know what to use as the addOrderby(???, 'DESC') value?
There are many bugs and workarounds required to achieve order by expressions as of v2.3.0 or below:
The order by clause does not support expressions, but you can add a field with the expression to the select and order by it. So it's worth repeating that Tjorriemorrie's own solution actually works:
$qb->select('b.year, COUNT(b.id) AS mycount')
->from('\My\Entity\Album', 'b')
->where('b.year IS NOT NULL')
->orderBy('mycount', 'DESC')
->groupBy('b.year');
Doctrine chokes on equality (e.g. =, LIKE, IS NULL) in the select expression. For those cases the only solution I have found is to use a subselect or self-join:
$qb->select('b, (SELECT count(t.id) FROM \My\Entity\Album AS t '.
'WHERE t.id=b.id AND b.title LIKE :search) AS isTitleMatch')
->from('\My\Entity\Album', 'b')
->where('b.title LIKE :search')
->andWhere('b.description LIKE :search')
->orderBy('isTitleMatch', 'DESC');
To suppress the additional field from the result, you can declare it AS HIDDEN. This way you can use it in the order by without having it in the result.
$qb->select('b.year, COUNT(b.id) AS HIDDEN mycount')
->from('\My\Entity\Album', 'b')
->where('b.year IS NOT NULL')
->orderBy('mycount', 'DESC')
->groupBy('b.year');
what is the error you get when using COUNT(b.id) AS count? it might be because count is a reserved word. try COUNT(b.id) AS idCount, or similar.
alternatively, try $qb->addOrderby('COUNT(b.id)', 'DESC');.
what is your database system (mysql, postgresql, ...)?
If you want your Repository method to return an Entity you cannot use ->select(), but you can use ->addSelect() with a hidden select.
$qb = $this->createQueryBuilder('q')
->addSelect('COUNT(q.id) AS HIDDEN counter')
->orderBy('counter');
$result = $qb->getQuery()->getResult();
$result will be an entity class object.
Please try this code for ci 2 + doctrine 2
$where = " ";
$order_by = " ";
$row = $this->doctrine->em->createQuery("select a from company_group\models\Post a "
.$where." ".$order_by."")
->setMaxResults($data['limit'])
->setFirstResult($data['offset'])
->getResult();`

Resources