Now that I've read all the DQL docs I still have some doubts, I'm
trying to do some nested condictions in my DQL however playing around
with DQL I can't seem to be able to archive them
To make myself more clear:
I have this DQL query
$q = Doctrine_Query::create()
->select('c.nombre,c.webpage')
->addSelect('COUNT(m.marca_id) as total_marcas')
->from('Corporativos c')
->leftJoin('c.Marcas m')
->groupBy('c.corporativo_id')
->where('ISNULL(c.deleted_at)')
->orwhere('c.nombre LIKE :nombre', array(':nombre'=>'%'.$srch))
->orWhere('c.nombre LIKE :nombre', array(':nombre'=>'%'.$srch.'%'))
->orWhere('c.nombre LIKE :nombre', array(':nombre'=>$srch.'%'))
->orderBy('c.nombre ASC')
->limit(0,20);
now this generates the following MySQL query:
SELECT c.corporativo_id AS c__corporativo_id, c.nombre AS c__nombre,
c.webpage AS c__webpage, COUNT(m.marca_id) AS m__0 FROM corporativos c
LEFT JOIN marcas m ON c.corporativo_id = m.corporativo_id WHERE
(ISNULL(c.deleted_at) OR c.nombre LIKE :nombre OR c.nombre
LIKE :nombre OR c.nombre LIKE :nombre) GROUP BY c.corporativo_id ORDER
BY c.nombre ASC
However I'm getting a set of results where either deleted_at is null
or the other conditions is completed, I'd like to make the
isnull(deleted_at) obligatory, if we were talking in terms of SQL the
query would look like this:
SELECT c.corporativo_id AS c__corporativo_id, c.nombre AS c__nombre,
c.webpage AS c__webpage, COUNT(m.marca_id) AS m__0 FROM corporativos c
LEFT JOIN marcas m ON c.corporativo_id = m.corporativo_id WHERE
(ISNULL(c.deleted_at) AND (c.nombre LIKE :nombre OR c.nombre
LIKE :nombre OR c.nombre LIKE :nombre)) GROUP BY c.corporativo_id
ORDER BY c.nombre ASC
you can see that I just changed the first OR statement for an AND and
added a couple of parenthesis to group the LIKE conditions.
Is it posible to archivie this in DQL using the same ->where()
notation avoiding writing down the whole condition ?
thanks :)
Not sure how recently this change was made, but for anyone like me coming to this question looking for answers long after this question was asked, the query builder now has ways to accomplish nested AND/OR logic: andX() / orX() functions.
You can use Doctrine_Query::andWhere, but i think this will factor your statement the wrong way, so you could build your query like
->where('c.nombre LIKE :nombre', array(':nombre'=>'%'.$srch))
->andWhere('ISNULL(c.deleted_at)')
->orWhere('c.nombre LIKE :nombre', array(':nombre'=>'%'.$srch.'%'))
->andWhere('ISNULL(c.deleted_at)')
->orWhere('c.nombre LIKE :nombre', array(':nombre'=>$srch.'%'))
->andWhere('ISNULL(c.deleted_at)')
which is kind of creepy.
Here is another solution with modifies Doctrine to be capable of custom bracketing: http://danielfamily.com/techblog/?p=37
Related
I tested the code below it works fine on phpmyadmin
SELECT registered_user_tbl.username, follow.follower_id FROM registered_user_tbl
INNER JOIN follow
ON follow.follower_id= 5 and registered_user_tbl.user_id= 5
I now want to implement the array version on my pdo project but it is not working kindly check and review query below
$this->db->select("SELECT registered_user_tbl.username, follow.follower_id FROM registered_user_tbl
INNER JOIN follow
ON follow.follower_id= :fid and registered_user_tbl.user_id= :fid",
(":fid" =>$user));
The 2nd parameter to your select() method should probably be an array so the round brackets are incorrect, for your data parameters.
And you cannot reuse :fid twice in the parameter substitution.
So try this
$this->db->select(
"SELECT registered_user_tbl.username, follow.follower_id
FROM registered_user_tbl
INNER JOIN follow ON follow.follower_id= :fid1
and registered_user_tbl.user_id= :fid2",
[":fid1" =>$user, ":fid2" =>$user]
);
I'm trying to run a raw SQL query, inside a Controller class, and I'm having trouble to figure out why I can't bind more than one parameter. Take a look at the snippet below:
$sql = "select
u.id,
u.name,
u.email,
r.name as role
from user u
inner join role r on r.id = u.role_id
left join user_group_user ugu on ugu.user_id = u.id and ugu.user_group_id = ".$user_group_id."
where (u.name like :search or u.email like :search or r.name like :search)
and ugu.user_id is null and u.id not in( :notIn )
order by u.name, r.name";
$users = $this->db->query($sql, ['search' => '%'.$search.'%', 'notIn'=>$notInStr ])->fetchAll();
The $notIn variable has a value like 1,2,3. If I do the same thing only with the parameter :search the query works. When I try with both parameters (:search and :notIn) the query returns but the :notIn seems to not have effect in the query. It looks like it is not being bound.
How can I run this query considering both parameters?
Thanks for any help
UPDATE:
The binding is actually working but it is binding the :notIn as a string, so the executed query is .... not in ('1,2,3')
I have solved my problem just making sure that everything is a number and just concatenating in the query: ...u.id not in( ".$notInStr." )
Standard pdo library which phalcon is using and which phalcon db is wrapping doesn't accept array as bound parameter. You would need to use phalcon models.
Make use of Phalcon\Mvc\Model\Query\Builder. There is a inWhere method, that accepts array as parameter.
Remember to never use not filtered data that You get from end-user, like You just did. This makes Yours application vulnerable to SQLInjection attacks.
Haven't been able to find a solid solution for this, but I have a mySQL query that I want to translate to Doctrine. It is a select from a subquery with joins and I might have read somewhere that joins are not allowed in subqueries in Doctrine.
Here is the SQL:
SELECT part, SUM(qty) as qty FROM (SELECT part, SUM(qty) as qty FROM sub LEFT JOIN main ON main.id = main_id WHERE hold != 1 GROUP BY name, part) AS tbl GROUP BY part
This is what I tried and it is all wrong.
$em = $this->getDoctrine()->getManager();
$q = $em->createQuery('v');
$q2 = $em->createSubQuery()
->select('m.part, sum(s.qty) qty')
->from('Sub s')
->leftJoin('s.main m')
->where('s.hold != 1')
->groupBy('m.part');
$q->select('m.part, sum(qty)', $q2->getDQL());
One of the first error I got was:
FatalErrorException: Error: Call to undefined method Doctrine\ORM\EntityManager::createSubQuery() in ....Controller.php line 238
I am pretty sure it isn't just this that I'm doing wrong but it is the first thing that's coming up. So getManager() apparently doesn't have a createSubQuery() function? What is the right way to do this?
There's no method like createSubQuery(). Take a look at that answer: https://stackoverflow.com/a/10763358
So I need to select data from a MySQL table by looking into one field and see if it has a certain word in it and do a whole lot of other things in the where clause which is dynamically generated.
In the old days with the old mysql extension I would do this:
select [bunch of stuff] left join [bunch of stuff] where
`field` rlike "(?=.*word1)(?=.*word2)(?=.*word3)..."
and [more where..] order by [order stuff]
Now of course I use mysqli and a prepared statement...
select [bunch of stuff] left join [bunch of stuff] where
match(`field`) against(?,?,?...)
and [more where..] order by [order stuff]
Unfortunately I got a InnoDB table which means I don't have full text search which would bring me to chain some like statement together like so:
select [bunch of stuff] left join [bunch of stuff] where
`field` like concat("%",?,"%") or `field` like concat("%",?,"%") ...
and [more where..] order by [order stuff]
But this would mean it breaks the "and" chain I have going here and would need to repeat [more where..] in every "or".... This has got to be wrong and I have been staring at this for too long now.
Any ideas?
You can build your query with array:
$sql="SELECT...WHERE ";
$cond=array();
$bind=array();
$subCond=array()
foreach($searchQuery as $txt) //assumed you have stored search query
{
$subCond[]="`field` LIKE concat('%',?,'%')";
$bind[]=$txt;
}
$cond[]="(".implode(" OR ",$subCond).")";
/*...continue to build conditions...*/
$sql.=implode(" AND ",$cond);
$sql.=" SORT BY ...";
$stmt=$mysqli->prepare($sql);
call_user_func_array(array($stmt,"bind_param"),array_merge(array(str_repeat("s",count($bind))),$cond));
$stmt->execute();
Noted that the above code was not tested, and may raise warning (possible due to the pass by reference issue), but it gives you the idea.
Also check out this comment for a variable-number-variable-binding solution.
I'm trying to build a query with the doctrine query builder which joins a non related table like this:
$query = $this->createQueryBuilder('gpr')
->select('gpr, p')
->innerJoin('TPost', 'p')
->where('gpr.contentId = p.contentId')
But this doesn't work. I still get an error:
Error: Identification Variable TPost used in join path expression but was not defined before.
I searched for this error message and everybody answered to use the table alias + attribute like p.someAttribute. But the table I want to join isn't related in the table I start my select from.
As a normal mysql query i would write it like this:
SELECT * FROM t_group_publication_rel gpr
INNER JOIN t_post p
WHERE gpr.content_id = p.content_id
Any ideas what i'm doing wrong?
Today I was working on similar task and remembered that I opened this issue. I don't know since which doctrine version it's working but right now you can easily join the child classes in inheritance mapping. So a query like this is working without any problem:
$query = $this->createQueryBuilder('c')
->select('c')
->leftJoin('MyBundleName:ChildOne', 'co', 'WITH', 'co.id = c.id')
->leftJoin('MyBundleName:ChildTwo', 'ct', 'WITH', 'ct.id = c.id')
->orderBy('c.createdAt', 'DESC')
->where('co.group = :group OR ct.group = :group')
->setParameter('group', $group)
->setMaxResults(20);
I start the query in my parent class which is using inheritance mapping. In my previous post it was a different starting point but the same issue if I remember right.
Because it was a big problem when I started this issue I think it could be also interesting for other people which don't know about it.
Joins between entities without associations were not possible until version 2.4, where you can generate an arbitrary join with the following syntax:
$query = $em->createQuery('SELECT u FROM User u JOIN Blacklist b WITH u.email = b.email');
Reference: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html
Want to improve this post? Add citations from reputable sources by editing the post. Posts with unsourced content may be edited or deleted.
$dql = "SELECT
a, md.fisrtName , md.LastName, mj
FROM MembersBundle:Memberdata md
INNER JOIN MembersBundle:Address a WITH md = a.empID
INNER JOIN MembersBundle:Memberjob mj WITH md = mj.memberData
...
WHERE
a.dateOfChange IS NULL
AND WHERE
md.someField = 'SomeValue'";
return $em->createQuery( $dql )->getResult();
A DQL join only works if an association is defined in your mapping. In your case, I'd say it's much easier to do a native query and use ResultSetMapping to populate your objects.