Doctrine2: createQueryBuilder which has an innerJoin with more than one condition - symfony

I basically want to do this SQL statement:
SELECT * FROM Table1
JOIN Table2
ON (
Table2.ID = Table1.THIS_ID
OR
Table2.ID = Table1.THAT_ID
)
Using createQueryBuilder and NOT createQuery.
Is it possible?
All the examples I can find only deal with a single condition and don't tackle the issue of AND/OR within a join.
Thanks.

You can try something like that (in a repository for instance):
$qb = $this->createQueryBuilder('t1');
$qb->join('t1.table2', 't2', Expr\Join::WITH, 't2.id = t1.thisId OR t2.id = t1.thatId');
...

You can do it like this:
$qb->leftJoin(
'u.Phonenumbers',
'p',
Expr\Join::WITH,
$qb->expr()->orx(
$qb->expr()->eq('t.this_id', 't1.id'),
$qb->expr()->eq('t.this_id', 't1.id')
)
)

Related

SQLITE unwanted behavior on group_concat in query

I have two tables like this:
Fiddle: click here
My query:
select
f.id,
'{{' || group_concat(f.key||','||ifnull(f.value,'NULL'), '},{')||'}}' as
key_value_pair_1,
'{{' || group_concat(r.key||','||ifnull(r.value,'NULL'), '},{')||'}}' as
key_value_pair_2
FROM items_functions as f
LEFT JOIN items_functions_2 as r ON f.id = r.id
GROUP BY f.id
But this results into a strange behavior. All results where shown multiple times as you can see when you run the above linked fiddle.
But what I want is a result like this:
id key_value_pair_1 key_value_pair_2
214808 {{16,662},{17,808},{33,1},{60,2}} {{16,662},{17,808},{33,1},{60,2}}
214809 {{16,902},{17,1103},{33,1},{60,2}} {{16,902},{17,1103},{33,1},{60,2}}
218965 {{19,808},{21,662},{33,1},{60,8}} {{19,808},{21,662},{33,1},{60,8}}
218966 {{19,1103}{21,902},{33,1},{60,8}} {{19,1103},{21,902},{33,1},{60,8}}
244574 {{16,999},{18,999},{54,174}} {{16,999},{18,999},{54,174}}
I guess my query has to be adjusted. :)
Would be awesome, if anyone is happen to have a solution on this.
Thanks in advance!
Best regards,
Andreas
I believe the following will do what you want :-
SELECT
p1.id, p1.kvp1, p2.kvp2
FROM
(
SELECT
id,
'{{' || group_concat(key||','||ifnull(value,'NULL'), '},{')||'}}'
AS kvp1
FROM items_functions GROUP BY id
)
AS p1
JOIN
(
SELECT
id,
'{{' || group_concat(key||','||ifnull(value,'NULL'), '},{')||'}}'
AS kvp2
FROM items_functions_2 GROUP BY id
)
AS p2
ON p1.id = p2.id
Which produces :-

How I can create multiple join with DQL

How I can create multiple join with DQL , something like this in sql:
SELECT t,c,u FROM `user` AS t
LEFT JOIN (`contract` AS c, `car` AS u)
ON (t.id = c.`user_id` AND u.id = c.`unit_id` AND u.name = 'audi')
WHERE t.email = 'test#example.com';
Solve problem by another way, create sub-query:
$query = $this->createQueryBuilder('user')
->addSelect(
array('contract', 'car')
)
;
$query->leftJoin(
'user.contracts',
'contract',
Expr\Join::WITH,
'contract.id IN (
SELECT contract2.id
FROM DataBundle:User user2
INNER JOIN user2.contracts contract2
INNER JOIN contract2.car car2
WHERE user2.email = :email AND (
contract2.status = :status1 OR contract2.status = :status2
) AND car2.name = :name
)'
);
$query->leftJoin(
'contract.car',
'car'
);
$query->where('user.email = :email');
Maybe will be useful for someone.
See article for multiple join example :
DQL JOIN Syntax:
[[LEFT | INNER] JOIN <component_reference1>] [ON | WITH] <join_condition1> [INDEXBY] <map_condition1>,
[[LEFT | INNER] JOIN <component_reference2>] [ON | WITH] <join_condition2> [INDEXBY] <map_condition2>,
...
[[LEFT | INNER] JOIN <component_referenceN>] [ON | WITH] <join_conditionN> [INDEXBY] <map_conditionN>
You will end up with something like this:
SELECT user,contract,car
FROM user AS user
LEFT JOIN user.contract AS contract
LEFT JOIN contract.car AS car
WHERE user.email = 'test#example.com' AND car.name = 'audi';
Obviously you need to define your entities and set up the relations properly. I'd suggest following the example in the documentation and then working your way through a test case.
Please note that the use of abbreviations (t,c,u) for aliases has been declared a war crime by the United Nations and will be punished severally.

How can I order by match result in doctrine querybuilder?

I have a custom dql match function and would like to select the match result as 'score' before ordering by that score. How can I adjust the following query to achieve this?
$qb = $this->getEntityManager()->createQueryBuilder();
$qb
->select('i', 'bi')
->from('AdminBundle:Items', 'i')
->where('i.instock=1')
->leftJoin('AdminBundle:MyTable','bi',\Doctrine\ORM\Query\Expr\Join::WITH, 'i.id = bi.productId')
->andWhere('bi.productId IS NULL')
->andWhere('MATCH (i.brand, i.store, i.title, i.description, i.keywords) AGAINST (:search BOOLEAN) > 0')
->andWhere('i.instock = 1')
->setParameter('search', $searchString)
->setMaxResults( $limit )
;
$results = $qb->getQuery()->getArrayResult();
I do not know if I understand your question, do you want to add to your select what you have in your where (match...) and order by it?
You can add not-mapped selects like this:
$qb->addSelect('MY_FUNCTION(my.params) AS HIDDEN mySelectAlias')
In your case, sth like:
$qb->addSelect('(MATCH (i.brand, i.store, i.title, i.description, i.keywords) AGAINST (:search BOOLEAN)) AS HIDDEN mySelectAlias')
And in your order by:
$qb->orderBy('mySelectAlias', 'desc');
Complete example:
https://coderwall.com/p/o5snag

Need some help to translate query from createQuery() to queryBuilder()

I'm used to create query with createQuery() instead of queryBuilder, but I need to translate a query in a queryBuilder one to use in a EntityType to generate a form. Here is my query :
SELECT p FROM D2ECoreBundle:Player p,
D2ECoreBundle:LadderMatch lm,
D2ECoreBundle:PlayerComposition hpc
JOIN hpc.players hp,
D2ECoreBundle:PlayerComposition fpc
JOIN fpc.players fp
WHERE (lm.homePlayerComposition = hpc AND hp = p)
OR (lm.foreignPlayerComposition = fpc AND fp = p)
and here is what i thought it would be in queryBuilder but doesnt work :
$qb->select('p')
->from('D2ECoreBundle:Player', 'p')
->from('D2ECoreBundle:LadderMatch', 'lm')
->from('D2ECoreBundle:PlayerComposition', 'hpc')
->join('hpc.players', 'hp')
->from('D2ECoreBundle:PlayerComposition', 'fpc')
->join('fpc.players', 'fp')
->where('lm.homePlayerComposition = hpc' AND 'hp = p')
->orwhere('lm.foreignPlayerComposition = fpc' AND 'fp = p');
Does anyone know what I should change to have it working? Thanx for the answers!
When you query the DB with:
SELECT * FROM TableA T1, TableB T2 ....
in many implementations is the same as:
SELECT * FROM TableA T1 JOIN TableB T2 ON ... // this is INNER JOIN
So, instead of using from multiple times, do joins:
$qb->select('p')
->from('D2ECoreBundle:Player', 'p')
->join('p.ladderMatches', 'lm')
->join('p.playerComposition', 'hpc')
->join('hpc.players', 'hp')
->join('hp.playerCompossition', 'fpc')
->join('fpc.players', 'fp')
->where('lm.homePlayerComposition = hpc' AND 'hp = p')
->orwhere('lm.foreignPlayerComposition = fpc' AND 'fp = p');
Not sure if I got the relation correct but you get the point...
I eventually managed to do this. Here is my code :
$qb = $this->createQueryBuilder('lm')
->select('p')
->from('D2ECoreBundle:Player', 'p')
->join('lm.homePlayerComposition', 'hpc')
->join('hpc.players', 'hp')
->join('lm.foreignPlayerComposition', 'fpc')
->join('fpc.players', 'fp')
->where('lm.homePlayerComposition = hpc AND hp = p')
->orwhere('lm.foreignPlayerComposition = fpc AND fp = p');
return $qb;
And a very important thing, since I want to select player, but starting by the LadderMatch entity, I need to put this in LadderMatchRepository.php and not PlayerRepository.php like I did, because it affects the generat

Drupal 7 altering query in view

I'm trying to alter a query in a view using mymodule_views_pre_execute and have used devel to find the sql query it is currently using, which is below:
SELECT node.nid AS nid FROM node node LEFT JOIN field_data_field_date
field_data_field_date ON node.nid = field_data_field_date.entity_id AND
(field_data_field_date.entity_type = :views_join_condition_0 AND
field_data_field_date.deleted = :views_join_condition_1)
WHERE ((
(DATE_FORMAT(field_data_field_date.field_date_value, '%Y-%m-%d\T%H:%i') > :node_date_filter) )AND
(( (node.status = :db_condition_placeholder_2) )))
LIMIT 10 OFFSET 0
I am then re-doing this using the following:
$query = db_select("node", "n");
$query->addField("n", "nid");
$query->leftJoin("{field_data_field_date}", "{field_data_field_date}",
"n.nid = field_data_field_date.entity_id AND field_data_field_date.entity_type = 'node'
AND field_data_field_date.deleted = '0'");
$query->where("(DATE_FORMAT(field_data_field_date.field_date_value, '%Y-%m-%d\T%H:%i') > NOW())");
$query->where("n.status = '1'");
I've had to replace :views_join_condition_0 with 'node', :views_join_condition_1 with '0' and :node_date_filter to NOW() although i'm not sure if this is the correct way? If I leave :views_join_condition_0, :views_join_condition_1 and :node_date_filter in though it doesn't work?!
Use hook_view_query_alter(&$view, &$query) instead.

Resources