New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
selectFrom query fails using manipulateQuery with HAVING clause #592
Comments
Your case is very tricky. Can you try something: https://github.com/Abhoryo/APYDataGridBundle/blob/2.1.13/Grid/Source/Entity.php#L421 Change this block with this one: https://github.com/Abhoryo/APYDataGridBundle/blob/2.1.13/Grid/Source/Entity.php#L595 $result = $query->select($this->getFieldName($column, true))
->distinct()
->orderBy($this->getFieldName($column), 'asc')
->setFirstResult(null)
->setMaxResults(null)
->getQuery()
->getResult(); New block: $query->resetDQLPart('where');
$result = $query->addSelect($this->getFieldName($column, true))
->distinct()
->orderBy($this->getFieldName($column), 'asc')
->setFirstResult(null)
->setMaxResults(null)
->getQuery()
->getResult(); |
The error changed:
|
I just updated to the latest The line The error has changed again: Here is my generated clause: SELECT
c0_.state AS state0,
c1_.updated_at AS updated_at1,
f2_.username AS username2,
b3_.name AS name3,
(
SELECT
GROUP_CONCAT(DISTINCT p4_.name SEPARATOR ', ') AS sclr5
FROM
contract_items c5_
INNER JOIN parttypes p6_ ON c5_.parttype_id = p6_.id
INNER JOIN parttype_groups p4_ ON p6_.parttype_group_id = p4_.id
WHERE
c5_.contract_id = c1_.id
) AS sclr4,
(
SELECT
MAX(c7_.created_at) AS dctrn__2
FROM
contract_states c7_
WHERE
c7_.contract_id = c1_.id
) AS sclr6
FROM
contracts c1_
LEFT JOIN contract_states c0_ ON c1_.id = c0_.contract_id
LEFT JOIN fos_user f2_ ON c1_.project_manager_id = f2_.id
LEFT JOIN branches b3_ ON c1_.branch_id = b3_.id
HAVING
sclr6 = c0_.created_at The error makes sense so far. The @GRID\Source(columns="id, createdAt, updatedAt, states.createdAt, states.state, number, problemDescription, items.parttype.parttypeGroup.name:GroupConcat:Distinct, projectManager.username, branch.name", groupBy={})
/**
* @ORM\OneToMany(targetEntity="Plusquam\Bundle\ContractBundle\Entity\ContractState", mappedBy="contract")
* @ORM\OrderBy({"date" = "DESC"})
*
* @GRID\Column(type="datetime", field="states.createdAt:Max", title="Last updated")
* @GRID\Column(type="datetime", field="states.createdAt", title="Created at", visible=false)
* @GRID\Column(type="text", field="states.state", title="Current State", filter="select", selectFrom="source", defaultOperator="eq", operatorsVisible=false)
*/
private $states; Maybe my query manipulation is wrong? $grid->getSource()->manipulateQuery(
function ($query) use ($tableAlias) {
$selectLastUpdate = 'SELECT MAX(s2.createdAt) FROM Entity\ContractState s2'
. ' WHERE s2.contract = ' . $tableAlias . '.id';
$query->addSelect('(' . $selectLastUpdate . ') AS HIDDEN state_last_created');
$having = 'state_last_created = _states.createdAt'; # WRONG ALIAS `_states` ?!
$query->having($having);
} |
I was missing the column indeed afterwars in my
My error now is: A typo BTW! :) If I change the method by adding $grid->setColumnsOrder(array(
'id',
'createdAt',
'states.state',
'states.createdAt',
'updatedAt',
'state_last_created',
'parttype_group_name',
'number_full',
'projectManager.username',
'branch.name'
), false); I get: Based on the following DQL: SELECT
DISTINCT _a.id,
_states.state as states::state,
_states.createdAt as states::createdAt,
_a.updatedAt,
_projectManager.username as projectManager::username,
_branch.name as branch::name,
_states.state as states::state
FROM Entity\Contract _a
LEFT JOIN _a.states _states
LEFT JOIN _a.projectManager _projectManager
LEFT JOIN _a.branch _branch
ORDER BY _states.state asc |
I don't know why you have twice the column. |
I removed it from my $grid->setColumnsOrder(array(
'id',
#'states.state',
'states.createdAt',
'updatedAt',
'state_last_created',
'parttype_group_name',
'number_full',
'projectManager.username',
'branch.name'
), false); I removed the The problem seems to be produced inside the query building for I will re-add the columns and check the query builder. |
I checked out the DQL inside The DQL after cloning in line 593 looks correct: SELECT
_a.id,
_states.state as states::state,
_states.createdAt as states::createdAt,
_a.updatedAt,
_projectManager.username as projectManager::username,
_branch.name as branch::name
FROM Entity\Contract _a LEFT JOIN _a.states _states LEFT JOIN _a.projectManager _projectManager LEFT JOIN _a.branch _branch After running through the result it has changed to: SELECT
DISTINCT _a.id,
_states.state as states::state,
_states.createdAt as states::createdAt,
_a.updatedAt,
_projectManager.username as projectManager::username,
_branch.name as branch::name,
_states.state as states::state
FROM Entity\Contract _a LEFT JOIN _a.states _states LEFT JOIN _a.projectManager _projectManager LEFT JOIN _a.branch _branch ORDER BY _states.state asc and the duplicate column got added. The reason for this is the change you recommended: #$result = $query->select($this->getFieldName($column, true))
$result = $query->addSelect($this->getFieldName($column, true)) A possible workaround seems to be completely removing the (add)select part: $result = $query
#->select($this->getFieldName($column, true))
->distinct()
->orderBy($this->getFieldName($column), 'asc')
->setFirstResult(null)
->setMaxResults(null)
->getQuery()
->getResult()
; My GRID correctely displays the columns and populates the filters. But I can't tell what consequences this may have on the general functionality, @Abhoryo . |
The performance will drop if you keep the whole query. I think that what you do is overload. Why find the max date ? Just perform an order on this column. You already perform a groupConcat so you should have only the data of the good row. |
Thanks @Abhoryo , next week I will give a variation of my SQL a final chance. Without it and just a simple Hard to explain without a direct comparison. I will post the different queries and results in a GIST next week and maybe I'm lucky and the GRID can solve it. :) |
Hi @Abhoryo , I hope you get the idea of my SELECT c.id, c.number, cs.createdAt, cs.stateName,
(
SELECT MAX(cs2.createdAt)
FROM `contract_states` `cs2`
WHERE `cs2`.`contract_id` = `c`.`id`
) AS lastCreatedAt
FROM `contracts` `c`
JOIN `contract_states` `cs` ON `c`.`id` = `cs`.`contract_id`
WHERE 1
HAVING cs.createdAt = lastCreatedAt But I also realized that there is a better method which is simply using a SELECT c.id, c.number, cs.createdAt, cs.stateName
FROM `contracts` `c`
JOIN `contract_states` `cs` ON `c`.`id` = `cs`.`contract_id`
WHERE cs.createdAt = (
SELECT MAX(cs2.createdAt)
FROM `contract_states` `cs2`
WHERE `cs2`.`contract_id` = `c`.`id`
) I tried the following solution for this: $grid->getSource()->manipulateQuery(
function ($query) use ($tableAlias) {
$selectItems = 'SELECT GroupConcat(DISTINCT ciPtGr.name SEPARATOR \', \')
FROM Entity\ContractItem ci
JOIN ci.parttype ciPt
JOIN ciPt.parttypeGroup ciPtGr
WHERE ci.contract = ' . $tableAlias . '.id';
$query->addSelect('(' . $selectItems . ') AS parttype_group_name');
$selectLastUpdate = 'SELECT MAX(s2.createdAt)'
. ' FROM Entity\ContractState s2'
. ' WHERE s2.contract_id = ' . $tableAlias . '.id';
$query->andWhere('_states.createdAt = :lastCreatedAt')
->setParameter('lastCreatedAt', $selectLastUpdate);
}
); But for some reason the SELECT
c0_.id AS id0,
c1_.state AS state1,
c1_.created_at AS created_at2,
c0_.updated_at AS updated_at3,
c0_.problemdescription AS problemdescription4,
c0_.number AS number5,
f2_.username AS username6,
b3_.name AS name7,
(
SELECT
GROUP_CONCAT(DISTINCT p4_.name SEPARATOR ', ') AS sclr9
FROM
contract_items c5_
INNER JOIN parttypes p6_ ON c5_.parttype_id = p6_.id
INNER JOIN parttype_groups p4_ ON p6_.parttype_group_id = p4_.id
WHERE
c5_.contract_id = c0_.id
) AS sclr8
FROM
contracts c0_
LEFT JOIN contract_states c1_ ON c0_.id = c1_.contract_id
LEFT JOIN fos_user f2_ ON c0_.project_manager_id = f2_.id
LEFT JOIN branches b3_ ON c0_.branch_id = b3_.id
WHERE
c1_.created_at = ?
LIMIT
20 Parameters: ['SELECT MAX(s2.createdAt) FROM Plusquam\Bundle\ContractBundle\Entity\ContractState s2 WHERE s2.contract_id = _a.id']
|
The error occurs beacuse you cannot use a subquery inside parameters, it's more simple: $selectLastUpdate = 'SELECT MAX(s2.createdAt)'
. ' FROM Entity\ContractState s2'
. ' WHERE s2.contract = ' . $tableAlias . '.id';
$query->andWhere('_states.createdAt = (' . $selectLastUpdate . ')'); For those that like to use querybuilders for DQL: $query2 = $query->getEntityManager()->createQueryBuilder();
$query2->select($query2->expr()->max('s2.createdAt'))
->from('Entity\ContractState', 's2')
->where('s2.contract = ' . $tableAlias . '.id');
$lastCreatedAtDql = $query2->getDQL();
$query->andWhere('_states.createdAt = (' . $lastCreatedAtDql . ')'); |
Using subqueries as parameters seems to be possible by now, see this similar example:https://gist.github.com/webdevilopers/9f182b113c9130b2dc68#file-offeradmin_configuredatagridfilters_solved-php This should successfully work with this bundle too. |
This is the way I manipulate the query:
The generated query looks like this and works fine:
Now I would like to populate the
selectFrom
forbranches
fromquery
:This results in the folloqing SQL:
This query will fail:
'state_last_created': Error: 'state_last_created' is not defined.
Without the
HAVING
clause everything will work fine.But I think the problem is the remaining part of the manipulated query e.g. the
$selectLastUpdate
, right?The text was updated successfully, but these errors were encountered: