Where-Condition as IN(Subquery) with Doctrine2 in Symfony2.3.1 doesnt work - symfony

---- Done with Symfony2.3.1 and Doctrine2 ----
Sorry, i hope i was not too stupid to find a suitable solution for my problem. I try to build a Query for hours.
SELECT * FROM product
WHERE product_id in
(
SELECT product_id from (
SELECT count(*) as result_amount, product_id FROM product_x_attribut
JOIN productattribut on productattribut_id = productattribut.id
WHERE (
productkey = "price" and
stringType = "premium"
) or (
productkey = "size" and
stringType = "S"
)
GROUP BY product_id
HAVING result_amount = 2
) as temp
)
GROUP BY product_id
ORDER BY p0_.name ASC
This is the SQL which works fine in phpmyAdmin.
This can be seen like
Select * from abc where abc.x in ( Select * from ( select * from ) as abcd )
So there is one core query, i call it subSubQuery, the second query around the core will be called subQuery and the outer Query is just the outer Query, no a Subquery.
I could build the subSubQuery with Doctrine2.
But i cannot built the subQuery like this
Select product_id from ( $subSubQuery->getQuery()->getDQL() )
I want to do the subQuery like this
$subQuery = $repositoryProduct->createQueryBuilder('product');
$subQuery->add('select', 'product_id');
$subQuery->add('from',$subSubQuery->getDQL() );
// However to set an alias is a miracle for me, this didnt work off course
$subQuery->add('as','tmp' );
This is the subQuery.
I also cannot build the outer Query
Select * from abc where abc.x in ( $subQuery->getQuery()->getDQL() )
I want to do this like this
$query->where(
$query->expr()->in('product.id', $subQuery->getDQL() )
);
But i try to build this with Doctrine2 like this:
I am so down, i tried ->getSQL(), ->getDQL(), i tried as much as i was able to detect as a suitable tiny step to a solution for this problem and i has tried as much keyword in google as my finger were able to write... I hope someone could help me to find a solution...
Thanks a lot to each helpful advise.

I know that statements like this work:
$qbGames->andWhere($qbGames->expr()->in('game.id',$qbGameId->getDQL()));
Your question is kind of hard to follow. Consider using pastebin to show all your mappings as they currently exist. And then maybe presenting a simplieid query?
My $qbGameId query was built with:
$qbGameId = $em->createQueryBuilder();
$qbGameId->addSelect('distinct gameGameId.id');
$qbGameId->from('ZaysoCoreBundle:Event','gameGameId');
// Assorted joins and where conditions

Related

DELETE from same table used in the WHERE

I have the following query that is supposed to delete from a table with a circular FK requirement;
DELETE FROM question
WHERE defaultGotoQuestionId IN (
SELECT id from question WHERE facilityId IN (
SELECT id FROM facility WHERE customerId NOT IN (1,76)
)
);
But I get the following error;
Table is specified twice, both as a target for 'DELETE' and as a separate source for data
I understand the error message - that I can't DELETE from a TABLE that I am specifying in the WHERE - I just can't seem to work out how to solve it, for myself.
I saw a few examples of using a join - but perhaps I am having an off day - because I have been iterating through copy/paste examples - but still can't manage it.
It works as a SELECT : In that the result gives me the records I want to delete;
SELECT id FROM question
WHERE defaultGotoQuestionId IN (
SELECT id from question WHERE facilityId IN (
SELECT id FROM facility WHERE customerId NOT IN (1,76)
)
);
Thanks for any help!
What version of MariaDB are you using?
DELETE :: Same Source and Target Table
Until MariaDB 10.3.1, deleting from a table with the same source and target was not possible. From MariaDB 10.3.1, this is now possible.
See dbfiddle.
In older versions of MariaDB (or in MySQL, for example), one option you can use is:
DELETE
`question`
FROM
`question`
INNER JOIN (
SELECT
`id`
FROM
`question`
WHERE
`defaultGotoQuestionId` IN (
SELECT
`id`
FROM
`question`
WHERE
`facilityId` IN (
SELECT
`id`
FROM
`facility`
WHERE
`customerId` NOT IN (1, 5)
)
)
) `der` ON
`question`.`id` = `der`.`id`;
See dbfiddle.

How to do arithemtic operations with an alias in sqlite

I want to calculate with an alias in sqlite (Example is modified from http://www.sqlitetutorial.net):
if i do it like this, i get the error message "no such column: tracks_count"
SELECT albumid,
title,
(
SELECT count(trackid)
FROM tracks
WHERE tracks.AlbumId = albums.AlbumId
)
tracks_count, tracks_count * album_nr
FROM albums
ORDER BY tracks_count DESC;
if i do it like this, i get zero for the mulitplication
SELECT albumid,
title,
(
SELECT count(trackid)
FROM tracks
WHERE tracks.AlbumId = albums.AlbumId
)
tracks_count, "tracks_count" * album_nr
FROM albums
ORDER BY tracks_count DESC;
Table data for the example:
table albums
table tracks
You don't even need a subquery here:
SELECT
a.albumid,
a.title,
COUNT(t.albumid) AS tracks_count,
COUNT(t.albumid) * a.album_nr AS other_count
FROM albums a
LEFT JOIN tracks t
ON a.albumid = t.albumid
GROUP BY
a.albumid,
a.title;
If you wanted to make your current approach work, then the problem you are having is that you are referring to the tracks_count alias in the same select in which it was defined. This isn't allowed, because the alias may not have even been computed yet. But, I would recommend using the answer I gave above.

CREATE TABLE with CTE statement

Is it possible to create a table from a query with a CTE statement?
Something like:
CREATE TABLE db1.test1 AS
(
WITH cte1(v1) as
( SEL v1 FROM db1.table1 )
SEL * FROM cte1
)
This is how the CTE's look like:
WITH employees(id, name, boss, senior_boss) AS
(
SEL
empls.id,
empls.name,
supervisors.name as boss,
senior_bosses.name as senior_boss
FROM empl_cte AS empls
LEFT JOIN empl_cte AS supervisors ON empls.boss_id = supervisors.id
LEFT JOIN empl_cte AS senior_bosses ON supervisors.boss_id = senior_bosses.id
),
WITH empl_cte(....) AS
(
SEL
id,
name
boss_id
FROM all_employees
WHERE <some_filters>
)
SEL
*
FROM products
LEFT JOIN employees ON products.sales_rep_id = employees.id
Both
converting the CTEs into views
and
converting employees as a sub-query (empl_cte as a VIEW) in the left join
leads to a massive loss of performance (run time blowing up from a couple of minutes to days of work). I can't figure out how Teradata optimizer works.
EXPLAIN on the new refactored queries seem indicate that the LEFT JOIN becomes a product join draining countless of time.
This will work in V16 (and possibly earlier versions).
CREATE TABLE myTable AS (
SELECT * FROM (
WITH x AS (
SELECT ...
FROM ...
WHERE ...
)
SELECT ...
FROM x ...
WHERE ...
) D
) WITH DATA PRIMARY INDEX (PK)
;
Basically you need to wrap the whole query, including the CTE, in a SELECT with an alias.

Doctrine Query Builder, "between" expression and subquery

I'm trying to create a quite complex query with Doctrine's Query Builder (I'm using Doctrine 2.2). In the model, i have a Distributor class and a DistributorVisit class with a one-to-many relationship. Every time a Distributor is visited by a representative, a new row is added to the DistributorVisit table with the visit date. An ER diagram of the two tables can be found here.
Now i want to be able to filter Distributors by their last visit date. So the user enters a date range (last visit from and last visit to) and Distributors whose last visit date is between those two dates are listed. I'm using Doctrine's Query Builder because there are a lot of other conditional queries I do in the filter, and I found the object-oriented approach to work best in this scenario. Here's what i did in the DistributorRepository class:
$qb = $this->getEntityManager()->createQueryBuilder()
->select('o')
->from('MyBundle:Distributor', 'o');
// Lots of 'andWhere's here
$qbv = $this->getEntityManager()->createQueryBuilder();
$qb->andWhere($qb->expr()->between(
$qbv->select($qbv->expr()->max('v.visitDate'))
->from('MyBundle:DistributorVisit', 'v')
->join('MyBundle:Distributor', 'o2',
Join::WITH,
$qbv->expr()->andX(
$qbv->expr()->eq('o2.id', 'v.distributorId'),
$qbv->expr()->eq('o2.id', 'o.id')
))
->getDQL(),
$filter->getLastVisitFrom()->getTimestamp(),
$filter->getLastVisitTo()->getTimestamp()
));
This gives me the following error:
[Syntax Error] line 0, col 83: Error: Expected Literal, got 'SELECT'
I guess this is because the Query Builder expects a literal where my sub-select is, however, the result of the sub-query should be a literal, right? May it be because the Query Builder does not add parenthesis accordingly?
Thanks a lot for your help.
I now resolved the issue the following way:
$qb = $this->getEntityManager()->createQueryBuilder()
->select('o')
->from('MyBundle:Distributor', 'o');
$qbdv = $this->getEntityManager()->createQueryBuilder();
$qbdv->select('MAX(dv2.visitDate)')
->from('MyBundle:DistributorVisit', 'dv2')
->where($qbdv->expr()->eq('dv2.distributor', 'o'));
$maxVisitDate = '('.$qbdv->getDQL().')';
$qb->leftJoin(
'o.distributorVisits',
'dv',
Join::WITH,
$qb->expr()->eq('dv.visitDate', $maxVisitDate)
);
$qb->andWhere(
$qb->expr()->between(
'dv.visitDate',
':dateFrom',
':dateTo'
)
)
->setParameter('dateFrom', $filter->getLastVisitFrom())
->setParameter('dateTo', $filter->getLastVisitTo());
So what I basically did is the following: I joined the DistributorVisit table to the Distributor table with the maximum visit date. The trick was the fact that one can pass the DQL of a (sub-)query ($qb1->getDQL()) directly to a Doctrine expression ($qb2->expr()->eq('column', $qb1->getDQL()). I did this with the left join in the code above.
I guess that your current DQL looks like this:
SELECT ..
FROM ..
WHERE SELECT .. FROM .. BETWEEN .. AND ..
But should look like this:
SELECT ..
FROM ..
WHERE (SELECT .. FROM ..) BETWEEN .. AND ..
To fix your code, i'd just put the subquery's dql inside parentheses:
$subQueryDQL = $qbv->select($qbv->expr()->max('v.visitDate'))
->from('MyBundle:DistributorVisit', 'v')
...
->getDQL();
$qb->andWhere($qb->expr()->between(
sprintf('(%s)', $subQueryDQL),
$filter->getLastVisitFrom()->getTimestamp(),
$filter->getLastVisitTo()->getTimestamp()
));
My case:
$qb->andWhere(
"t.field BETWEEN (
{$subQuerybuilder1->getDQL()}
) AND (
{$subQuerybuilder2->getDQL()}
)
");
Got:
SELECT ... WHERE t.field BETWEEN (
SELECT t1.field FROM t1
) AND (
SELECT t2.field FROM t2
)

symfony2 doctrine join

Okay, so i've got a query that i've researched and researched how to get this to work and for the life of me i cant!... perhaps i'm just doing this incorrectly and the minimal information ive found..
I've got a table named timeclock setup.. which has a field: noteBy_id in it which is an id to the user the record belongs to...
What I need to do now, is for the management side of things in the system.. I anticipate more than 1 company using this timeclock system, and as such I need to filter the results based on the company id.. In the user table, i have a field named parentcompany_id
So, lets see if I can express in words what I need to do..
I need to Select * from timeclock and left join user.parentcompany_id where timeclock.daydate < :start and where u.parentcompany = :pid
where start is: `date('Y-m-d 00:00:00');
I've setup this query:
$em = $this->getDoctrine()->getEntityManager();
$start = date('Y-m-d 00:00:00');
$qb = $em->getRepository('EcsCrmBundle:TimeClock');
$qb = $qb->createQueryBuilder('t');
$query = $qb->select('t, u.parentcompany_id')
->from('timeclock', 't')
->leftJoin('Ecs\AgentManagerBundle\Entity\User', 'u', 'ON' 'u.id = t.noteBy_id AND u.parentcompany_id = :pid')
->where('t.daydate < :start')
->andWhere("t.noteBy_id != ''")
->setParameter('start', $start)
->setParameter('pid', $user->getParentcompany())
->getQuery();
$entities = $query->getArrayResult();
I've looked and looked and can't find a solution to the error that I get which is:
An exception has been thrown during the rendering of a template ("[Semantical Error] line 0, col 112 near 'u ON u.id = t.noteBy_id': Error: Identification Variable Ecs\AgentManagerBundle\Entity\User used in join path expression but was not defined before.") in EcsCrmBundle:TimeClock:manager.html.twig at line 5.
and the query that gets output is:
SELECT t, u.parentcompany_id FROM Ecs\CrmBundle\Entity\TimeClock t LEFT JOIN Ecs\AgentManagerBundle\Entity\User u ON u.id = t.noteBy_id AND u.parentcompany_id = :pid, timeclock t LEFT JOIN Ecs\AgentManagerBundle\Entity\User u ON u.id = t.noteBy_id AND u.parentcompany_id = :pid WHERE t.daydate < :start AND t.noteBy_id != ''
which under normal circumstances would work perfectly... but in this, it just doesn't... Any ideas?
I've recently had to do it like this.. I'm guessing in this that your noteBy is a ManyToOne in the user table and you are wanting to have it filter the results by the company of the admin that is currently logged into your system..
So, adapting a join I had to write myself for such a task is easy enough. I personally like to use the QueryBuilder so this will be done in query builder..
Your first mistake in your query is the ->from('timeclock', 't') line. Because you have previously created your object with $qb = $em->getRepository('EcsCrmBundle:TimeClock'); $qb = $qb->createQueryBuilder('t'); you don't need the from in the query builder, as it will be generated for you.
The next issue, is the leftJoin and I'll explain why when I've shown you a working version.
And the last issue, preventing this from working how you want it - is a missing andWhere clause. So, lets take a look at a working query.
$query = $qb->select('t, u')
->leftJoin('t.noteBy', 'u', 'WITH', 'u.id = t.noteBy')
->where('t.daydate < :start')
->andWhere('u.parentcompany = :pid')
->setParameter('start', $start)
->setParameter('pid', $user->getParentcompany())
->getQuery();
So because we've already created the object by using $qb = $qb->createQueryBuilder('t') we just select t and u
For the join, we're joining the timeclock table by the noteBy column, which is the user id from the user table. So, the first argument being the "from" alias. So, since we've aliased the timeclock table with t we use t.noteBy. The next argument in the leftjoin is the alias of the 2nd table, which is u in this case but can be anything.. The third argument for a leftJoin anyway - is the way you join it.. either a WITH or ON will work here. and the 4th argument, is the match you wish it to have.. in this case u.id must equal t.noteBy
You will see that I got rid of one of the andWhere, I did this because with the properly structured query you shouldn't need it. I did however add in the andWhere for the u.parentcompany since that is afterall what you are looking to filter by you should have it in a WHERE instead of as a match in the join itself.
The documentation is very limited in this, and it took me a while to figure it all out as well.. You, undoubtedly - like me, came to using doctrine from writing your queries by hand. And So since you seem to be just starting with Symfony (i am myself as well about 2 months in now), you're still in the hand-coding mindset. But with further time, you'll start understanding the DQL way of life. Try this query out and see what happens.
Ok, first you would need to relate entity Timeclock to Company. Whenever you want to join two entities in Doctrine they need to be related by some attribute (that is, table column).
I don't see any need for User entity in this query as all info is available through Company entity and you are not filtering down results based on any user properties.
You desired query should look something like this (more or less). I took liberty and ditched _id suffixes from entity attributes as they tend to cloud what is really going on. ;)
$query = $this->getEntityManager()->createQuery("SELECT t, c.id FROM EcsCrmBundle:TimeClock t JOIN t.company c WHERE c.id = :pid AND t.daydate < :start AND t.noteBy != ''");
$query->setParameter('start', $start);
$query->setParameter('pid', $user->getParentcompany());
return $query->getArrayResult();
Also, I did inner-join (JOIN) as I think there could not be timeclock without it's company but feel free to change that to LEFT JOIN if that suits you better.
Is this what you were trying to achieve?

Resources