I'm currently using symfony2, doctrine 2.3 and PostgreSQL 9. I've been searching for a couple of hours now to see HOW on earth do I do a ILIKE select with QueryBuilder.
It seems they only have LIKE. In my situation, though, I'm searching case-insensitive.
How on earth is it done?
// -- this is the "like";
$search = 'user';
$query = $this->createQueryBuilder('users');
$query->where($query->expr()->like('users.username', $query->expr()->literal('%:username%')))->setParameter(':username', $search);
// -- this is where I get "[Syntax Error] line 0, col 86: Error: Expected =, <, <=, <>, >, >=, !=, got 'ILIKE'
$search = 'user';
$query = $this->createQueryBuilder('users');
$query->where('users.username ILIKE :username')->setParameter(':username', $search);
I don't know about Symfony, but you can substitute
a ILIKE b
with
lower(a) LIKE lower(b)
You could also try the operator ~~*, which is a synonym for ILIKE
It has slightly lower operator precedence, so you might need parenthesis for concatenated strings where you wouldn't with ILIKE
a ILIKE b || c
becomes
a ~~* (b || c)
The manual about pattern matching, starting with LIKE / ILIKE.
I think this guy had the same problem and got an answer:
http://forum.symfony-project.org/viewtopic.php?f=23&t=40424
Obviously, you can extend Symfony2 with SQL vendor specific functions:
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.1/cookbook/dql-user-defined-functions.html
I am not a fan of ORMs and frameworks butchering the rich functionality of Postgres just to stay "portable" (which hardly ever works).
This works for me (Symfony2 + Doctrine 2)
$qq = 'SELECT x FROM MyBundle:X x WHERE LOWER(x.y) LIKE :y';
$q = $em->createQuery($qq)->setParameter(':y', strtolower('%' . $filter . '%'));
$result = $q->getResult();
Unfortunately, we still do not have the ability to create custom comparison operators...
But we can create a custom function in which we implement the comparison.
Our DQL query well look like this:
SELECT q FROM App\Entity\Customer q WHERE ILIKE(q.name, :name) = true
The class describing the ILIKE function will look like this:
class ILike extends FunctionNode
{
/** #var Node */
protected $field;
/** #var Node */
protected $query;
/**
* #param Parser $parser
*
* #throws \Doctrine\ORM\Query\QueryException
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->field = $parser->StringExpression();
$parser->match(Lexer::T_COMMA);
$this->query = $parser->StringExpression();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* #param SqlWalker $sqlWalker
*
* #return string
* #throws \Doctrine\ORM\Query\AST\ASTException
*/
public function getSql(SqlWalker $sqlWalker)
{
return '(' . $this->field->dispatch($sqlWalker) . ' ILIKE ' . $this->query->dispatch($sqlWalker) . ')';
}
}
The resulting SQL will look like this:
SELECT c0_.id AS id_0,
c0_.name AS name_1,
FROM customer c0_
WHERE (c0_.name ILIKE 'paramvalue') = true
From what I am aware, search queries in Symfony2 (at least when using Doctrine) are case in-sensitive. As noted in the Doctrine QL docs:
DQL is case in-sensitive, except for namespace, class and field names, which are case sensitive.
Related
I am trying to use postgresql jsonb operators with spring data jpa query as:
#Query(value="SELECT * from Employee e WHERE e.details #> '{\"province\":{\"city\":{\"town\": \":town\"}}, \"hobbies\": [\":hobby\"]}'",nativeQuery = true)
town and hobby are inputs.
There is no error but no result is returned, though records are there which meets the criteria
It seems parameter binding is not working.
What can be the solution?
Here, :town and :hobby is inside ''(single quote) means string literal, so parameter can't be replaced. You can use || to concat as string so that parameters are not inside in '' and can be replaced.
#Query(value="SELECT * from Employee e WHERE e.details #> ''||'{\"province\":{\"city\":{\"town\": \"' || :town || '\"}}, \"hobbies\": [\"' || :hobby || '\"]}'||'' ", nativeQuery = true)
I got a problem to make a "simple" query with the Doctrine QueryBuilder.
I try to get some "persons" which are on 10 km max.
My query :
$QB = $this->createQueryBuilder('p');
$QB->add('select', 'p')
->add('from', 'MyProject\Bundle\FrontBundle\Entity\Pro p')
->where('p.job = :job')
->andWhere('(3956 * 2 * ASIN(SQRT( POWER(SIN((:latitude - abs(pro.latitude)) * pi()/180 / 2),2) + COS(:latitude * pi()/180 ) * COS(abs(pro.latitude) * pi()/180) * POWER(SIN((:longitude - pro.longitude) * pi()/180 / 2), 2) ))) <= 10')
->addOrderBy('p.dateCreation', 'DESC')
->addOrderBy('p.id', 'DESC')
->setParameter('latitude', $latitude)
->setParameter('longitude', $longitude)
->setParameter('job', $jobId);
The problem is on the second 'where' statement, Doctrine fails on "ASIN" because of the parenthesis that follows. It tries to execute the function...
Is there a way to escape it ? Or another way to construct this condition ?
Thanks for Doctrine professional ;)
If I understand correctly, you can either write a raw SQL query for that, or implement the function ASIN(or any other) in doctrine.
Here you have a bundle that might help:
https://github.com/wiredmedia/doctrine-extensions
You can use its implementation of ASIN function:
https://github.com/wiredmedia/doctrine-extensions/blob/master/lib/DoctrineExtensions/Query/Mysql/Asin.php
And and article about custom DQL functions:
http://symfony.com/doc/current/cookbook/doctrine/custom_dql_functions.html
I am using SphinxQL to query Sphinxsearch engine. I want to simulate the SPH_MATCH_ANY which is implemented in the php API like this :
$cl->SetMatchMode(SPH_MATCH_ANY);
$cl->Query("test query", "index");
=> search for docs matching with "test" OR "query"
So, I have written a function (php) to replace spaces and other special chars with pipes (|) in order to use it with SphinxQL :
function formatQuery($str) {
return trim(preg_replace('/[^-_\'a-z0-9]+/', '|', $str), ' |');
}
$str = "test query";
$sql = "SELECT * FROM index WHERE MATCH('" . addslashes(formatQuery($str)) . "')";
=> SELECT * FROM index WHERE MATCH('test|query');
The problem is, for some characters like - (minus), it can break the query, example :
$str = "i-phone is great";
$sql = "SELECT * FROM index WHERE MATCH('" . addslashes(formatQuery($str)) . "')";
=> SELECT * FROM index WHERE MATCH('i-phone|is|great')
=> ok
$str = "i - phone is great";
$sql = "SELECT * FROM index WHERE MATCH('" . addslashes(formatQuery($str)) . "')";
=> SELECT * FROM index WHERE MATCH('i|-|phone|is|great')
=> broken query because of "|-|"
Do you know a better way to make SphinxQL queries work in SPH_MATCH_ANY mode? or a better regexp to make it works for all cases?
I know I could use a more restrictive regexp like this:
preg_replace('/[^a-z0-9]+/', '|', $str)
but it would split strings like "i-phone is great" in 'i|phone|is|great' and I don't want that...
Thank you,
Nico
One way might be to use quorom
$sql = "SELECT * FROM index WHERE MATCH('\"" . addslashes($str) . "\"/1')";
you will need to add - to your charset_table tho, so it becomes part of a word.
The other option is
$query = preg_replace('/(\w+?)[-\'](\w+?)/','$1~$2',$query);
$query = preg_replace('/[^\w\~]+/','|',$query);
$query = preg_replace('/(\w+~\w[\w~]*)/e','"\"".str_replace("~"," ","$1")."\""',$query);
To turn it into a phrase.
I want to use joins in zend. Below is my query
$select = $this->_db->select()
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
->join(array('tenderapplications' => 'procurement_tbltenderapplications','tendersupplier' => 'tblsupplier'),
'tenderapplications. TenderInvitationContractorID=tendersupplier.UserID');
I have UserID in tendersupplier table. but its giving following error :-
Column not found: 1054 Unknown column 'tendersupplier.UserID' in 'on clause
I think its not the right way to include more than one tale in same array of a join.
Try code like this..
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
->join(array('tenderapplications' => 'procurement_tbltenderapplications'),
'tenderapplications.TenderInvitationContractorID=tblsupplier.UserID');
I am not sure whether you are planning to join values from tblsupplier table also.
The where condition is not written the way you did .
I dount that tblsupplier is a table then it should be in an array
This code is not tested!
$select = $this->_db->select()
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria. TenderId=evaluationcriteria.TenderId')
->join(array('tenderapplications' => 'procurement_tbltenderapplications'), array('tendersupplier' => 'tblsupplier'))
->where('tenderapplications. TenderInvitationContractorID=tendersupplier.UserID');
Looks like you are trying to join 2 tables in one ->join, I don't think you can do that.
join code from Zend_Db_Select()
/**
* Adds a JOIN table and columns to the query.
*
* The $name and $cols parameters follow the same logic
* as described in the from() method.
*
* #param array|string|Zend_Db_Expr $name The table name.
* #param string $cond Join on this condition.
* #param array|string $cols The columns to select from the joined table.
* #param string $schema The database name to specify, if any.
* #return Zend_Db_Select This Zend_Db_Select object.
*/
public function join($name, $cond, $cols = self::SQL_WILDCARD, $schema = null)
{
return $this->joinInner($name, $cond, $cols, $schema);
}
Here is the comment block from from()
/**
* Adds a FROM table and optional columns to the query.
*
* The first parameter $name can be a simple string, in which case the
* correlation name is generated automatically. If you want to specify
* the correlation name, the first parameter must be an associative
* array in which the key is the correlation name, and the value is
* the physical table name. For example, array('alias' => 'table').
* The correlation name is prepended to all columns fetched for this
* table.
*
* The second parameter can be a single string or Zend_Db_Expr object,
* or else an array of strings or Zend_Db_Expr objects.
*
* The first parameter can be null or an empty string, in which case
* no correlation name is generated or prepended to the columns named
* in the second parameter.
*
* #param array|string|Zend_Db_Expr $name The table name or an associative array
* relating correlation name to table name.
* #param array|string|Zend_Db_Expr $cols The columns to select from this table.
* #param string $schema The schema name to specify, if any.
* #return Zend_Db_Select This Zend_Db_Select object.
*/
Maybe try something like this instead:
$select = $this->_db->select()
//FROM table procurement_tbltenderevaluationcriteria AS evaluationcriteria, SELECT FROM
//COLUMNS ScoringCriteriaID and ScoringCriteriaWeight
->from(array('evaluationcriteria' => 'procurement_tbltenderevaluationcriteria'),
array('ScoringCriteriaID','ScoringCriteriaWeight'))
//JOIN TABLE procurement_tbltenderscoringcriteria AS scoringcriteria WHERE
//TenderId FROM TABLE scoringcriteria == TenderId FROM TABLE evaluationcriteria
->join(array('scoringcriteria' => 'procurement_tbltenderscoringcriteria'),
'scoringcriteria.TenderId=evaluationcriteria.TenderId')
//JOIN TABLE procurement_tbltenderapplications AS tenderapplications
->join(array('tenderapplications' => 'procurement_tbltenderapplications'))
//JOIN TABLE tblsupplier AS tendersupplier WHERE TenderInvitationContractorID FROM TABLE
// tenderapplications == UserID FROM TABLE tendersupplier
->join(array('tendersupplier' => 'tblsupplier'),
'tenderapplications.TenderInvitationContractorID=tendersupplier.UserID');
you may also need to alter your select() definition to allow joins:
//this will lock the tables to prevent data corruption
$this->_db->select(Zend_Db_Table::SELECT_WITHOUT_FROM_PART)->setIntegrityCheck(FALSE);
I hope I'm reading your intent correctly, this should get you closer if not all the way there. (one hint, use shorter aliases...)
I'm trying to use fetchAll on a query that has 2 variables. I can't figure out the syntax.
I can manage with only 1 variable:
$sql = "SELECT * FROM mytable WHERE field1 = ?";
$this->_db->fetchAll($sql,$value1); # that works
However I'm having some issues when query has multiple variables
$sql = "SELECT * FROM mytable WHERE field1 = ? AND field2 = ?";
$this->_db->fetchAll($sql,$value1,$value2); # doesn't work
$this->_db->fetchAll($sql,array("field1"=>$value1,"field2"=>$value2)); # doesn't work either
The reason why I want to use ? instead of placing the variables directly into the query is that I've learned that using ? allows for the query to be compiled generically by the db engine and improves performances.
There are two types of parameter, named parameters and positional parameters. You're mixing the two types and that won't work.
Named parameters match a placeholder by name. Names are started with the : symbol. The parameter names are not the same as the names of the columns you happen to use them for. You supply parameter values in an associative array, using the parameter name (not the column name) as the array keys. For example:
$sql = "SELECT * FROM mytable WHERE field1 = :param1 AND field2 = :param2";
$this->_db->fetchAll($sql,array("param1"=>$value1,"param2"=>$value2));
Positional parameters use the ? symbol for the placeholder. You supply parameter values using a simple (non-associative) array, and the order of values in the array must match the order of parameter placeholders in your query. For example:
$sql = "SELECT * FROM mytable WHERE field1 = ? AND field2 = ?";
$this->_db->fetchAll($sql,array($value1,$value2));
Most brands of SQL database natively support only one style or the other, but PDO attempts to support both, by rewriting the SQL if necessary before preparing the query. Since Zend_Db is modeled after PDO, Zend_Db also supports both parameter styles.
This question is a bit old, but I thought I'd just add to it for reference sake.
I would recommend starting to use Zend_Db_Select with Zend_Db. I've been doing a lot with Zend_Db lately. More from Zend_Db_Select reference guide.
Lets assume you have a Zend_Db adapter: $this->_db
# this will get the Zend_Db_Select object
$select = $this->_db->select();
# now you build up your query with Zend_Db_Select functions
$select->from('mytable');
$select->where('field1 = ?', $field1);
$select->where('field2 = ?', $field2);
[...]
# echo to see the SQL (helps in debugging)
# SELECT * FROM mytable WHERE field1 = ? AND field2 = ? [...]
echo '<p>My SQL: ' . $select . '</p>';
# Execute the SQL / Fetch results
$results = $select->query()->fetchAll();
That's the basics from your given example, but the Zend Framework reference guide on the select object has a lot of good information on how to build even more complex queries with JOINS, UNIONS, GROUP BY, LIMIT, HAVING, etc.
If you wanted to use an alias name for a table or parameters, you use an associative array with the alias name being the index value:
# SELECT p.* FROM products AS p
$select->from('p' => 'products');
If you want to return only selected fields, you add an array of field names as a second parameter:
# SELECT model FROM products
$select->from(products, array(model));
Actually, the above could should produce fully qualified SQL as:
SELECT 'products'.model FROM 'products'
but I wrote the above for brevity and clarity in the example.
One thing I just came across is using AND and OR in the WHERE condition.
# WHERE a = $a
$select->where('a = ?', $a);
# WHERE a = $a AND b = $b
$select->where('a = ?', $a);
$select->where('b = ?', $b);
# WHERE a = $a OR b = $b
$select->where('a = ?', $a);
$select->orWhere('b = ?', $b);
# WHERE a = $a AND b = $b
$select->orWhere('a = ?', $a);
$select->where('b = ?', $b);
Notice, that whatever the following "where" function you use, will combine with the previous statement as that operand. Ok, that sounded confusing.
If the second "where" is an "OR" it will be an "OR" conditional. If the second "where" is a "AND" the statement will be "AND".
In other words, the first WHERE function is ignored in terms of what condition it will use.
In fact, I just asked a question on Stack Overflow yesterday regarding doing a complex WHERE using select.
Hope that helps!
Cheers!
Try this:
$sql = "SELECT * FROM mytable WHERE field1 = ? AND field2 = ?";
$statement = $this->_db->query($sql,array("field1"=>$value1,"field2"=>$value2));
$data = $statement->fetchAll();
$this->_db must be an instance of Db adapter.
Heres the actual Zend way to code for this.
$sql = "SELECT * FROM mytable WHERE field1 = :param1 AND field2 = :param2";
$this->_db->fetchAll($sql,array("param1"=>$value1,"param2"=>$value2));
$where = $this->_db->select()
->from('mytable')
->where('field1 = ?',$value1)
->where('field2 = ?',$value2);
$rowSet = $this->_db->fetchAll($where);
This works great for me