say i have a nvarchar field in my database that looks like this
1, "abc abccc dabc"
2, "abccc dabc"
3, "abccc abc dabc"
i need a select LINQ query that would match the word "abc" with boundaries not part of a string
in this case only row 1 and 3 would match
from row in table.AsEnumerable()
where row.Foo.Split(new char[] {' ', '\t'}, StringSplitOptions.None)
.Contains("abc")
select row
It's important to include the call to AsEnumerable, which means the query is executed on the client-side, else (I'm pretty sure) the Where clause won't get converted into SQL succesfully.
Maybe a regular expression like this (nb - not compiled or tested):
var matches = from a in yourCollection
where Regex.Match(a.field, ".*\sabc\s.*")
select a;
datacontext.Table.Where(
e => Regex.Match(e.field, #"(.*?[\s\t]|^)abc([\s\t].*?|$)")
);
or
datacontext.Table.Where(
e => e.Split(' ', '\t').Contains("abc");
);
For efficiency, you want to do as much of the filtering as possible on the server, and then the rest of the filtering on the client. You can't use Regex on the server (SQL Server doesn't support it) so the solution is to first use a LIKE-type search (by calling .Contains) then use Regex on the client to further refine the results:
db.MyTable
.Where (t => t.MyField.Contains ("abc"))
.AsEnumerable() // Executes locally from this point on
.Where (t => Regex.IsMatch (t.MyField, #"\babc\b"))
This ensures that you retrieve only the rows from SQL Server than contain the letters 'abc' (regardless of whether they're a word-boundary match or not) and use Regex on the client-side to further restrict the result set so that only matches that are on word boundaries are included.
Related
I am trying to query query the current month, here is my query:
$clients = $this->Clients;
$query = $clients->find();
if($this->Auth->user('role') !== 'admin'){
$query->where(['user_id =' => $this->Auth->user('id')]);
$query->where(['MONTH(dob) = ' => 'EXTRACT(month FROM (NOW()))']);
$query->order(['dob' => 'ASC']);
}
It returns 0 records (my field is a date type), however this query in phpmyadmin works:
SELECT * FROM `clients` WHERE MONTH(dob) = EXTRACT(month FROM (NOW()))
What am I doing wrong?
Just look at the actual generated query (check out your DBMS query log, or try DebugKit), it will look different, as the right hand side value in a key => value condition set is subject to parameter-binding/casting/quoting/escaping. In your case it will be treated as a string, so the condition will finally look something like:
WHERE MONTH(dob) = 'EXTRACT(month FROM (NOW()))'
That will of course not match anything.
You could pass the whole SQL snippet as a single array value, or as an expression object, that way it would be inserted into the query as is (do not insert user values that way, that would create an SQL injection vulnerability!), but I'd suggest to use portable function expressions instead.
CakePHP ships with functions expressions for EXTRACT and NOW, so you can simply do something like:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$query->where(function (QueryExpression $exp, Query $query) {
return $exp->eq(
$query->func()->extract('MONTH', new IdentifierExpression('dob')),
$query->func()->extract('MONTH', $query->func()->now())
);
});
Looks a bit complicated, but it's worth it, it's cross DBMS portable as well as auto-quoting compatible. The generated SQL will look something like
WHERE EXTRACT(MONTH FROM (dob)) = (EXTRACT(MONTH FROM (NOW())))
See also
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions
Cookbook > Database Access & ORM > Query Builder > Using SQL Functions
API > \Cake\Database\Expression\QueryExpression::eq()
API > \Cake\Database\FunctionsBuilder::extract()
API > \Cake\Database\FunctionsBuilder::now()
I have following sql query in my hbm file. The SCHEMA, A and B are schema and two tables.
select
*
from SCHEMA.A os
inner join SCHEMA.B o
on o.ORGANIZATION_ID = os.ORGANIZATION_ID
where
case
when (:pass = 'N' and os.ORG_ID in (:orgIdList)) then 1
when (:pass = 'Y') then 1
end = 1
and (os.ORG_SYNONYM like :orgSynonym or :orgSynonym is null)
This is a pretty simple query. I had to use the case - when to handle the null value of "orgIdList" parameter(when null is passed to sql IN it gives error). Below is the relevant java code which sets the parameter.
if (_orgSynonym.getOrgIdList().isEmpty()) {
query.setString("orgIdList", "pass");
query.setString("pass", "Y");
} else {
query.setString("pass", "N");
query.setParameterList("orgIdList", _orgSynonym.getOrgIdList());
}
This works and give me the expected output. But I would like to know if there is a better way to handle this situation(orgIdList sometimes become null).
There must be at least one element in the comma separated list that defines the set of values for the IN expression.
In other words, regardless of Hibernate's ability to parse the query and to pass an IN(), regardless of the support of this syntax by particular databases (PosgreSQL doesn't according to the Jira issue), Best practice is use a dynamic query here if you want your code to be portable (and I usually prefer to use the Criteria API for dynamic queries).
If not need some other work around like what you have done.
or wrap the list from custom list et.
Let's suppose I have a table: Person(Name: univarchar) and this table contains a row "abc".
I search Person by using Hibernate (Criteria API and HQL):
Criteria API:
Criteria c = session.createCriteria(Person.class);
c.add(Restrictions.ilike(name,"abc"));
return c.list();
HQL:
String query = "from Person where lower(name) like :name";
Query q = session.createQuery(query);
query.setString("name","abc");
return query.list();
It return empty result. However, when I use Interactive SQL of Sybase to execute SQL statement that is generated by Hibernate, it return a row "abc".
I found a solution for HQL case. This is to use rtrim function:
String query = "from Person where lower(rtrim(name)) like :name";
...
But my problem is I want to use Criteria API and I cannot find any ways to trim name column by using Criteria API.
Thanks and sorry for my poor English.
Have you tried with this code :
Criteria c = session.createCriteria(Person.class);
c.add(Restrictions.ilike(name,"abc",MatchMode.ANYWHERE));
return c.list();
If this will not work then Read this. Its similar Just he wants to trim while Order you want to trim while Restrictions.
I am using Doctrine2 and Zf2 , now when I need to fetch count of rows, I have got the following two ways to fetch it. But my worry is which will be more optimized and faster way, as in future the rows would be more than 50k. Any suggestions or any other ways to fetch the count ?? Is there any function to get count which can be used with findBy ???
Or should I use normal Zf2 Database library to fetch count. I just found that ORM is not preferred to fetch results when data is huge. Please any help would be appreciated
$members = $this->getEntityManager()->getRepository('User\Entity\Members')->findBy(array('id' => $id, 'status' => '1'));
$membersCnt = sizeof($members);
or
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('count(p)')
->from('User\Entity\Members', 'p')
->where('p.id = '.$id)
->andWhere('p.status = 1');
$membersCnt = $qb->getQuery()->getSingleScalarResult();
Comparison
1) Your EntityRepository::findBy() approach will do this:
Query the database for the rows matching your criteria. The database will return the complete rows.
The database result is then transformed (hydrated) into full PHP objects (entities).
2) Your EntityManager::createQueryBuilder() approach will do this:
Query the database for the number of rows matching your criteria. The database will return a simple number (actually a string representing a number).
The database result is then transformed from a string to a PHP integer.
You can safely conclude that option 2 is far more efficient than option 1:
The database can optimize the query for counting, which might make the query faster (take less time).
Far less data is returned from the database.
No entities are hydrated (only a simple string to integer cast).
All in all less processing power and less memory will be used.
Security comment
Never concatenate values into a query!
This can make you vulnerable to SQL injection attacks when those values are (derived from) user-input.
Also, Doctrine2 can't make use of prepared statements / parameter binding, which can lead to some performance-loss when the same query is used often (with or without different parameters).
In other words, replace this:
->where('p.id = '.$id)
->andWhere('p.status = 1')
with this:
->where('p.id = :id')
->andWhere('p.status = :status')
->setParameters(array('id' => $id, 'status' => 1))
or:
->where($qb->expr()->andX(
$qb->expr()->eq('p.id', ':id'),
$qb->expr()->eq('p.status', ':status')
)
->setParameters(array('id' => $id, 'status' => 1))
Additionally
For this particular query, there's no need to use the QueryBuilder, you can use straight DQL in stead:
$dql = 'SELECT COUNT(p) FROM User\Entity\Members p WHERE p.id = :id AND p.status = :status';
$q = $this->getEntityManager()->createQuery($dql);
$q->setParameters(array('id' => $id, 'status' => 1));
$membersCnt = $q->getSingleScalarResult();
You should totally go to the dql version of the count.
With the first method you will hydrate (convert from db resultset to objects) each of the rows as single object and put them on one array and then count the amount items in that array. That will be a totally waste of memory and cycles if the only objective is to know the number of elements in that result set.
With the second method the dql will be gracefully converted to SELECT COUNT(*) Blah blah blah
plain SQL sentence and will retrieve directly the count from db.
The comment about ORM is not preferred to when to retrieve data is huge is true, in big batch process you should paginate your query to retrieve data instead all at the same time to avoid memory overrides but in that case you are only retrieving a single number, the total count so this rule doesn’t apply.
Query builder is so slow .
Use DQL for faster select .
$query = $this->getEntityManager()->createQuery("SELECT count(m) FROM User\Entity\Members m WHERE m.status = 1 AND m.id = :id ");
$query->setParameter(':id', $id);
You need setParameter for prevent SQL injection .
Stored procedure is fastest but it depend on your DB .
Make all relations of entity Lazy.
Is it possible to run a case-insensitive cypher query on neo4j?
Try that: http://console.neo4j.org/
When I type into this:
start n=node(*)
match n-[]->m
where (m.name="Neo")
return m
it returns one row. But when I type into this:
start n=node(*)
match n-[]->m
where (m.name="neo")
return m
it does not return anything; because the name is saved as "Neo". Is there a simple way to run case-insensitive queries?
Yes, by using case insensitive regular expressions:
WHERE m.name =~ '(?i)neo'
https://neo4j.com/docs/cypher-manual/current/clauses/where/#case-insensitive-regular-expressions
Another way would be:
WHERE LOWER(m.Name) = LOWER("Neo")
And if you are using the Neo4j Client (.NET):
Client.Cypher.Match("(m:Entity)")
.Where("LOWER(m.Name) = LOWER({name})")
.WithParam("name", inputName)
.Return(m => m.As<Entity>())
.Results
.FirstOrDefault();
If anybody is looking on how to do this with a parameter, I managed to do it like this.
query = "{}{}{}".format('Match (n) WHERE n.pageName =~ "'"(?i)", name, '" RETURN n')
and "name" is the variable or your parameter
You can pass a parameter to the case insensitive regular expression like:
WHERE m.name =~'(?i)({param})