Doctrine Search by count on join Table - sql

I have a problem with my nemesis: SQL/DQL
I have an entity: Style and an entity Vote. A Style can have a lot of Votes (as you can imagine) and one Vote is linked to exactly one Style.
I now want to search for Styles that have less Votes than a Specific Amount (it's user input, but let's say it is 5). This is the code I use with the querybuilder
$qb = $this->createQueryBuilder('s');
$qb
->select("s")
->join('s.votes', 'v')
->addSelect("COUNT(v.id) as voteCount")
->where("voteCount < ?1")
->orderBy('voteCount', "DESC")
->setMaxResults(3)
->setFirstResult(0)
->groupBy('s.id')
->setParameter(1, 5);
$query = $qb->getQuery();
$result = $query->getResult();
Once I try to execute the query, it basically says, that i voteCount is not known in the where clause. Here is the exact Error Message
An exception occurred while executing 'SELECT s0_.active AS active0, s0_.views AS views1, s0_.description AS description2, s0_.name AS name3, s0_.id AS id4, s0_.updated AS updated5, s0_.created AS created6, COUNT(v1_.id) AS sclr7, s0_.battle_id AS battle_id8, s0_.user_id AS user_id9, s0_.voucher_id AS voucher_id10 FROM Style s0_ INNER JOIN Vote v1_ ON s0_.id = v1_.style_id WHERE sclr7 < ? GROUP BY s0_.id ORDER BY sclr7 DESC LIMIT 3 OFFSET 0' with params [1]:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sclr7' in 'where clause'
What did I do wrong? How can I search vor the voteCount?

Conditions for aggregate functions such as sum and count should be put in a having clause.
$qb = $this->createQueryBuilder('s');
$qb->select("s");
$qb->join('s.votes', 'v');
$qb->addSelect("COUNT(v.id) as voteCount");
$qb->orderBy('voteCount', "DESC");
$qb->setMaxResults(3);
$qb->setFirstResult(0);
$qb->groupBy('s.id');
$qb->having("count(v.id) < ?1"); //changed from where
$qb->setParameter(1, 5);
$query = $qb->getQuery();
$result = $query->getResult();

You cannot reference a column alias in the WHERE clause.
Change
$qb->where("voteCount < ?1");
To
$qb->where("COUNT(v.id) < ?1");

Related

How to make this type of query in Laravel?

This is the sql query but how can I do it in laravel?
SELECT id FROM clientes where email is null and phone is null and id in(SELECT DISTINCT(cliente_id) FROM reservas WHERE dia < now())
This is the code that I tried to make:
$usersIdDel = DB::table("clientes")->select('id')
->whereNotNull('email')->whereNotNull('phone')
->whereIn('id',function($query){ $query->select('cliente_id')->from('reservas')->distinct()->where('dia','<',date('Y-m-d'));
})
->get();
$clientes = Cliente::select()->orderBy('nombre', 'desc')->get();
return view('admin.clientes.index')->with(compact('clientes'));
There are two queries anyway so..
$clientIds = DB::table('reservas')->select('cliente_id')->distinct()->where('dia','<',date('Y-m-d'))->get();
then,
$usersIdDel = DB::table("clientes")->select('id')
->whereNotNull('email')->whereNotNull('phone')
->whereIn('id', $clientIds->pluck('cliente_id')->all())
->get();
You can simply do that without thinking about the complexity of converting or splitting queries to multiple query builder statements.
$sql = "SELECT id FROM clientes where email is null and phone is null and id in(SELECT DISTINCT(cliente_id) FROM reservas WHERE dia < now())";
$result = DB::select($sql);

QueryBuilder - IN expression

I've created a quiz and I record in DB if people answered right to all question and the time they take to finish the quiz.
I'm trying to create a querybuilder to retrieve the guy who answered correct to the maximum of questions with the minimum of time.
My table looks like this :
So, the request (which works) I did in SQL in the DB is :
SELECT
id
FROM
public.user_quizz
WHERE
quizz_id = 4
AND
number_correct_answers IN (SELECT max(number_correct_answers) FROM user_quizz WHERE quizz_id = 4)
AND
answered_in IN (SELECT min(answered_in) FROM user_quizz WHERE quizz_id = 4);
Of course, I don't know if it's the best (and the most optimal) request we could do in this case, but it works.
Now, I'm trying to translate this query into querybuilder.
I'm blocked on the IN expression. I don't know how I could do the SELECT here.
$qb = $this->createQueryBuilder('u');
$query = $qb->select('u')
->andWhere(
$qb->expr()->eq('u.quizz', ':quizzId'),
$qb->expr()->in(
'u.numberCorrectAnswers',
)
)
->setParameter('quizzId', $quizz->getId())
->getQuery()
;
Thanks for your help.
$qbSelectMax = $this->createQueryBuilder('uc') // user copy, to prevent alias collisions
$qbSelectMax
->select($qb->expr()->max('uc.numberCorrectAnswers'))
->where($qb->expr()->eq('uc.quizz', ':quizzId'));
$qb = $this->createQueryBuilder('u')
$query = $qb->select('u')
->andWhere(
$qb->expr()->eq('u.quizz', ':quizzId'),
$qb->expr()->in(
'u.numberCorrectAnswers',
$qbSelectMax->getDQL()
)
)
->setParameter('quizzId', $quizz->getId())
->getQuery();
You can create sub DQL query to select max numberCorrectAnswers first and then pass DQL right into in parameter
ORDER BY could be used to sort by number of answers and less time taken:
$qb = $this->createQueryBuilder('u')
->orderBy('u.numberCorrectAnswers', 'DESC')
->addOrderBy('u.answeredIn', 'ASC');

Why does a UNION ALL query treat the outer ORDER column as unknown?

I'm using unionAll() and return the data perfectly, but I need ordernate the data and always return error because the column not exists.
$events = $this->Events
->find('available')
->where([
'Events.group_of_event_id IS NULL'
])
->select('Events.id')
->select('Events.name')
->select('Events.slug')
->select('Events.date_event_start')
->select([
'is_group' => 0
]);
$groups = $this->GroupOfEvents
->find('available')
->select('GroupOfEvents.id')
->select('GroupOfEvents.name')
->select('GroupOfEvents.slug')
->select('GroupOfEvents.date_event_start')
->select([
'is_group' => 1
]);
$limit = 10;
$page = 1;
if($this->request->query('limit'))
$limit = $this->request->query('limit');
if($this->request->query('page'))
$page = $this->request->query('page');
$offset = ($page - 1) * $limit;
$connection = ConnectionManager::get('default');
$union = $events->unionAll($groups)->epilog(
$connection
->newQuery()
->order(['date_event_start' => 'ASC'])
->limit($limit)
->offset($offset)
);
Return this error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'date_event_start' in 'order clause'
As the error states, there is no date_event_start column.
Unlinke normale SQL queries, where a non-table prefixed column would fall back to referring to one of the involved tables, similar doesn't happen for union results, with union results you have to explicity refer to the columns as they have been selected.
So you have to make sure that either the columns are selected without a table prefix, or to select and use proper aliases in the ORDER clause. In order to avoid ambiguity, I'd strongly suggest going for the latter, something like
->select(['date_event_start_alias' => 'Events.date_event_start'])
// ...
->select(['date_event_start_alias' => 'GroupOfEvents.date_event_start'])
// ...
->order(['date_event_start_alias' => 'ASC'])
It should be noted that at least with MySQL and Postgres (I'm not sure about other DBMS like SQLite or SQL Server), you actually have to set the alias only for the first SELECT. Setting it for all selects won't do any harm, so I'm including it in the example, but it's not actually necessary.
See also
Cookbook > Database Access & ORM > Query Builder > Selecting Data

Doctrine 2 - Outer join query

In the context of the SonataAdminBundle / SonataUserBundle, I'm using the query builder to add static filters to the "list" query :
With this query, I get only users in the group "Juge", the query works well :
$query
->leftJoin( $query->getRootAlias().'.groups', 'g')
->andWhere( 'g.name = :group_name' )
->setParameter('group_name', 'Juge');
In an other Admin class, i want to do the oposite of this query : get the users who ARE NOT in the "Juge" group. How can I perform this? There is not outerJoin function in doctrine 2 right?
I think you want to do
$query
->leftJoin( $query->getRootAlias().'.groups', 'g',
Expr\Join::WITH, 'g.name = :group_name')
->where('g.name IS NULL')
->setParameter('group_name', 'Juge');
where Expr is Doctrine\ORM\Query\Expr.
I used the following code and it works for me, its a kind of Outer Join.
$qb = $this->getEntityManager()->createQueryBuilder()
->select('u')
->from('UserBundle:User', 'u')
->leftJoin('u.group g WITH g.id = :groupId', false)
->where('g IS NULL')
->groupBy('u.id')
->setParameter('groupId', 12)
return $qb->getQuery()->getResult();

select from db sql query

I have this query :
$query = mysql_query ("SELECT *
FROM saledb.application
WHERE app_id = (
SELECT app_id
FROM saledb.applicationdetails
WHERE is_hot = '1'
) LIMIT $Kvet,$Zet
");
And I have the following error:
Unable to save result set in
/home/lemondo/lemondosales.itnovations.ge/content/tpl/gtpl/main.php on
line 68
When I changing select item with MAX(app_id) it works but i need show all results. i know where is problem mysql cant choose in one query meny ID but i need alternativ query.
Use the IN predicate instead of = like os:
SELECT *
FROM saledb.application
WHERE app_id IN
(SELECT app_id
FROM saledb.applicationdetails
WHERE is_hot = '1');
$query = mysql_query ("SELECT * FROM saledb.application WHERE app_id IN (SELECT app_id FROM saledb.applicationdetails WHERE is_hot = '1') LIMIT $Kvet,$Zet");
That should do the trick. If you leave '=' and the subquery returns more than one row, you wil get that error. To match all the lines in saledb.application that have the app_id in the result set you need to use "IN" :)