Symfony2 Doctrine SQL object mapping on subselect - symfony

I'm trying to use this query:
MySQL SELECT DISTINCT by highest value
SELECT
p.*
FROM
product p
INNER JOIN
( SELECT
magazine, MAX(onSale) AS latest
FROM
product
GROUP BY
magazine
) AS groupedp
ON groupedp.magazine = p.magazine
AND groupedp.latest = p.onSale ;
Within Symfony2 and DQL.
I have:
$query = $em->createQuery("SELECT p FROM MyBundle:Product p WHERE p.type = 'magazine' AND p.maglink IS NOT NULL OR (p.type = 'magazine' AND p.diglink IS NOT NULL) GROUP BY p.magazine ORDER BY p.onSale DESC");
Which works fine with and outputs objects but without the correct MAX(onSale)
Doing:
$query = $em->createQuery("SELECT p , MAX(p.onSale) FROM MyBundle:Product p WHERE p.type = 'magazine' AND p.maglink IS NOT NULL OR (p.type = 'magazine' AND p.diglink IS NOT NULL) GROUP BY p.magazine ORDER BY p.onSale DESC");
Results in non-objects being returned.
This:
$query = $em->createQuery("SELECT
p.*
FROM
MyBundle:Product p
INNER JOIN
( SELECT
p.magazine, MAX(onSale) AS p.latest
FROM
MyBundle:Product p
GROUP BY
p.magazine
) AS groupedp
ON groupedp.magazine = p.magazine
AND groupedp.latest = p.onSale ;");
Throws this error:
[Semantical Error] line 0, col 127 near 'SELECT
': Error: Identification Variable ( used in join path expression but was not defined before.
I assume due to this Symfony2 Doctrine query
How can I maintain my mapping while still being able to sort each item by onsale?

Have you considered splitting this into two queries:
First:
Run your query directly against the database connection, and return the IDs of the relevant rows, in the order you want. This separates your complex query from DQL.
Second:
Query the rows through Doctrine to get the full entities you want, based on the IDs/orders of the previous query.

This is a shot in the dark, but it seems fairly obvious. Your aliasing two tables to the same alias. Thus when your using p. in the join it thinks your working from the original definition of p from before the join, then you alias the join as p. Change the alias of the join (and the references to that table) so each alias is unique.

Related

Symfony Doctrine DQL how to add SELECT in a SUM of a main SELECT

Actually, i would like to reproduce with Doctrine this regular SQL Query :
SELECT SUM(b.nb_places * (SELECT pricing FROM param p WHERE t.date BETWEEN p.from_date AND p.to_date)) as gains from booking b INNER JOIN tour t ON b.tour_id = t.id;
That compute total gains according prices between two dates.
I wrote this DQL in a Repository :
public function allBooking() {
$query = $this->manager->createQuery(
'SELECT
SUM(b.nbPlaces * SELECT p.pricing FROM \App\Entity\Param p WHERE t.date BETWEEN p.fromDate AND p.toDate)
FROM App\Entity\Booking b JOIN b.tour t'
);
return $query->getResult();
}
But running this query, i got :
[Syntax Error] line 0, col 24: Error: Expected Literal, got 'SELECT' (500 Internal Server Error)
How do i acheive this query with DQL or using QueryBuilder ?
Thx for help
You forgot about putting
SELECT p.pricing FROM \App\Entity\Param p WHERE t.date BETWEEN p.fromDate AND p.toDate
into additional brackets.
It should looks like this:
$query = $this->manager->createQuery(
'SELECT SUM(b.nbPlaces * (SELECT p.pricing FROM \App\Entity\Param p WHERE t.date BETWEEN p.fromDate AND p.toDate))
FROM App\Entity\Booking b JOIN b.tour t'
);

Complex AX Query

i want to rebuild this SQL Query as AX Query.
I tried it in several ways, but I don't get it.
I am not completely new to AX queries, but I only have experience with some simple queries not with such complex SQL queries.
SELECT * FROM ( SELECT DH.[RECID] AS RECID_DIMENSIONHIERARCHY
,DH.[NAME] AS NAME__DIMENSIONHIERARCHY
,DH.[DESCRIPTION] AS DESC__DIMENSIONHIERARCHY
,DH.[PARTITION] AS PARTITION_DIMENSIONHIERARCHY
,DL.[DIMENSIONATTRIBUTE] AS RECID_DIMENSIONATTRIBUTE
,DA.[NAME] AS NAME_DIMENSIONATTRIBUTE
,DN.[RECID] AS RECID_DIMENSIONCONSTRAINTNODE
,DNC.[RECID] AS RECID_DIMENSIONCONSTRAINTNODECRITERIA
,DNC.[RANGETO] AS #Owner
,DNCR.[WILDCARDSTRING] AS #Agreement
FROM (SELECT * FROM [dbo].[DIMENSIONHIERARCHY]
WHERE [STRUCTURETYPE] = 1 AND [NAME] LIKE 'AG-OW%'
) AS DH
INNER JOIN [dbo].[DIMENSIONHIERARCHYLEVEL] AS DL
ON DH.[RECID] = DL.[DIMENSIONHIERARCHY]
AND DH.[PARTITION] = DL.[PARTITION]
INNER JOIN [dbo].[DIMENSIONATTRIBUTE] AS DA
ON DL.[DIMENSIONATTRIBUTE] = DA.[RECID]
AND DL.[PARTITION] = DA.[PARTITION]
INNER JOIN [dbo].[DIMENSIONCONSTRAINTNODE] AS DN
ON DL.[RECID] = DN.[DIMENSIONHIERARCHYLEVEL]
AND DL.[PARTITION] = DN.[PARTITION]
INNER JOIN [dbo].[DIMENSIONCONSTRAINTNODECRITERIA] AS DNC
ON DN.[RECID] = DNC.[DIMENSIONCONSTRAINTNODE]
AND DN.[PARTITION] = DNC.[PARTITION]
INNER JOIN [dbo].[DIMENSIONCONSTRAINTNODECRITERIA] AS DNCR
ON DN.[PARENTCONSTRAINTNODE] = DNCR.[DIMENSIONCONSTRAINTNODE]
AND DN.[PARTITION] = DNCR.[PARTITION]
) AS Sub
You need to break down your query and implement it in small chunks. Then combine all of it to get the desired result.
There are two ways to create query in X++.
Create query using select statement for example:
Select * from HcmWorker join * from DirPerson
where DirPerson.RecId == HcmWorker.Person
See this link : Select statement syntax
Create query with AOT structure. You might want to have a look at the following link:
Create query in AOT by using X++

Doctrine ManyToMany Query

I have a Product Entity which has a ManyToMany relationship with a Taxon Entity. I want to find all the products that belong to the intersection of all Taxons. For instance I want to find all products that belong to taxons with IDs 1 and 2.
Products
{1,2,3}
Taxons
{1,2,3,4,5}
ProductsToTaxons
{{p1,t1},{p1,t2}, {p2,t2}}
I want to retrieve the following set ONLY when querying products for taxons 1 and 2:
Product
{1}
which is from {{p1,t1}, {p1,t2}}
Okay, So here is the DQL that i tried... but it doesn't work?
SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t
WHERE t.id = 1 AND t.id = 2
(P.S. I would also do this with QueryBuilder with as well)
EDIT
To clarify, here is the SQL that I would like to translate into DQL/QueryBuilder.
select p.id
from product p
where exists (select product_id
from product_to_taxon
where taxon_id = 1
and product_id = p.id)
and exists (select product_id
from product_to_taxon
where taxon_id = 4
and product_id = p.id);
You can use the MEMBER OF statement to achieve this although in my experience it hasn't produced very performant results with a ManyToMany relationship:
In DQL:
SELECT p FROM SRCProductBundle:Product p
WHERE 1 MEMBER OF p.taxons OR 2 MEMBER OF p.taxons
Or with Query builder
$this->createQueryBuilder('p')
->where(':taxon_ids MEMBER OF p.taxons')
->setParameter('taxon_ids', $taxonIdsArray)
->getQuery()
->getResult();
This will create SQL similar to the example provided although in my experience it still had a join in the EXISTS subqueries. Perhaps future versions of Doctrine can address this.
I think you want something like this:
$qb = $this
->createQueryBuilder('p')
->select('p.id')
;
$qb
->leftJoin('p.taxons', 'taxon1', Join::WITH, 'taxon1.id = :taxonId1')
->setParameter('taxonId1', 1)
->andWhere($qb->expr()->isNotNull('taxon1'))
->leftJoin('p.taxons', 'taxon2', Join::WITH, 'taxon2.id = :taxonId2')
->setParameter('taxonId2', 2)
->andWhere($qb->expr()->isNotNull('taxon2'))
;
Which is equivalent to the SQL:
SELECT p.id
FROM products p
LEFT JOIN taxons t1 ON (p.id = t1.product_id AND t1.id = 1)
LEFT JOIN taxons t2 ON (p.id = t2.product_id AND t2.id = 2)
WHERE t1.id IS NOT NULL
AND t2.id IS NOT NULL
;
Your DQL has wrong logic. You can't have a taxon with both id=1 and id=4. You could do it like this:
SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t
WHERE t.id = 1 OR t.id = 4
But I would prefer this way:
SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t
WHERE t.id IN (1, 4)
Using query builder that would look something like this, assuming you're in EntityRepository class:
$this->createQueryBuilder('p')
->join('p.taxons', 't')
->where('t.id IN :taxon_ids')
->setParameter('taxon_ids', $taxonIdsArray)
->getQuery()
->getResult();
For lack of a clean way to do this with DQL, and after a considerable amount of research, I resorted to doing this in Native SQL. Doctrine allows Native SQL via the EntityManager with createNativeQuery().
So in short, I utilized this ability and constructed the SQL query included in my question as a string and then passed it to the createNativeQuery() function.
This does appear to have some drawbacks as it appears I will be unable to use the KnpPaginatorBundle with it... So I might end up just filtering the results in PHP rather than SQL, which I'm hesitant to do as I think there are performance drawbacks.

Semantical Error - Doctrine 2.0

These are my tables:
Table Gift:
-id
-price
...
Table Couple:
-id
-name
...
table registry: //provide a many-many relation between gifts and couples
-id
-coupleId
-giftId
table purchase:
-amount
-registryId
I already wrote a sql query to get all the gift info for a specific couple
$qb = $this->createQueryBuilder('g') //gift
->from('\BBB\GiftBundle\Entity\Registry', 'reg')
->select('g.id , g.price')
->where('reg.gift = g.id')
->andWhere('reg.couple = :coupleID')
->orderBy('reg.id','DESC')
->setParameter('coupleID', $coupleID);
OR
SELECT g.id , g.price,
FROM gift g, registry reg
WHERE reg.gift_id = g.id AND reg.couple_id = 1
I also want to get the total amount that for the gifts that have been bought (if any)
EX. SUM(purchase.amount) as totalContribute
I have tried:
$qb = $this->createQueryBuilder('g')
->from('\BBB\GiftBundle\Entity\Purchase', 'p')
->from('\BBB\GiftBundle\Entity\Registry', 'reg')
->select('g.id , g.price')
->addSelect('SUM(p.amount) as totalContribute')
->leftJoin('p','pp', 'ON','reg.id = pp.registry')
->where('reg.gift = g.id')
->andWhere('reg.couple = :coupleID')
->orderBy('reg.id','DESC')
->setParameter('coupleID', $coupleID);
but it gives me the following error:
[Semantical Error] line 0, col 145 near 'pp ON reg.id': Error: Identification Variable p used in join path expression but was not defined before.
First of all, you should define join condition in your SQL statements after joins, not in WHERE clause. The reason is that it's really not efficient. So the query shoul look like:
SELECT g.id , g.price,
FROM gift g JOIN registry reg ON reg.gift_id = g.id
WHERE reg.couple_id = 1
But about your Doctrine query, You get error because you're defining joins in wrong way. Your query should more like:
$qb = $this->createQueryBuilder('g') // You don't have put "from" beacuse I assume you put this into GiftRepository and then Doctrine knows that should be \BBB\GiftBundle\Entity\Gift
->select('g.id , g.price')
->addSelect('SUM(p.amount) as totalContribute')
->join('g.purchase','p') // pay attention for this line: you specify relation basing on entity property - I assume that is "$purchase" for this example
->leftJoin('p.registry', 'reg') // here you join with \BBB\GiftBundle\Entity\Purchase
->where('reg.couple = :coupleID')
->orderBy('reg.id','DESC')
->setParameter('coupleID', $coupleID);
Please treat this as pseudocode - I didn't check it works but it should like more like this.
One more thing - if your repository method returns object(s) of X entity you should put this method to XRepository.

update doctrine with join table

I am trying to update the field "note" in Note Entity which have a relation ManyToOne (bidirectionnel) with "ElementModule" and "Inscription", the entity "Inscription" have a relation ManyToOne with the "Etudiant" Entity
I tried this DQL Query:
$query = $this->_em->createQuery('update UaePortailBundle:Note u JOIN u.inscription i JOIN u.elementmodule e join i.etudiant et set u.note = ?3
where et.id = ?1 and e.id = ?2 ');
$query->setParameter(1, $etudiant);
$query->setParameter(2, $element);
$query->setParameter(3, $note);
$resultat = $query->execute();
i get this error
[Syntax Error] line 0, col 50: Error: Expected Doctrine\ORM\Query\Lexer::T_EQUALS, got 'i'
LEFT JOIN, or JOINs in particular are only supported in UPDATE statements of MySQL. DQL abstracts a subset of common ansi sql, so this is not possible. Try with a subselect or IDENTITY ( you must use the latest version of Doctrine 2.2.2 ) :
createQuery('update UaePortailBundle:Note u set u.note = ?3
where IDNETITY(u.inscription) = ?1 and IDENTITY(u.elementmodule) = ?2 ');
after searching and trying to find a solution for that using doctrine dql, i was not able to find it, so i used direct sql query to update the database.
$stmt = $this->getEntityManager()
->getConnection()
->prepare("update note set note = :note where `etudiant_id` like :etudiant_id and `elementmodule_id` like :elementmodule_id");
$stmt->bindValue('etudiant_id',$etudiant);
$stmt->bindValue('elementmodule_id' ,$element );
$stmt->bindValue('note', $note);
$stmt->execute();

Resources