String matching in Peewee (SQL) - sql

I am trying to query in Peewee with results that should have a specific substring in them.
For instance, if I want only activities with "Physics" in the name:
schedule = Session.select().join(Activity).where(Activity.name % "%Physics%").join(Course).join(StuCouRel).join(Student).where(Student.id == current_user.id)
The above example doesn't give any errors, but doesn't work correctly.
In python, I would just do if "Physics" in Activity.name, so I'm looking for an equivalent which I can use in a query.

You could also use these query methods: .contains(substring), .startswith(prefix), .endswith(suffix).
For example, your where clause could be:
.where(Activity.name.contains("Physics"))
I believe this is case-insensitive and behaves the same as LIKE '%Physics%'.

Quick answer:
just use Activity.name.contains('Physics')
Depending on the database backend you're using you'll want to pick the right "wildcard". Postgresql and MySQL use "%", but for Sqlite if you're performing a LIKE query you will actually want to use "*" (although for ILIKE it is "%", confusing).
I'm going to guess you're using SQLite since the above query is failing, so to recap, with SQLite if you want case-sensitive partial-string matching: Activity.name % "*Physics*", and for case-insensitive: Activity.name ** "%Physics%".
http://www.sqlite.org/lang_expr.html#like

Related

Is there an easier way to rewrite SQL Server queries for PostgreSQL?

In particular, I'm looking for a way to more easily rewrite my like queries without having to use the "lower" function each time.
In SQL Server, my query would look like this:
WHERE (FIELD LIKE '%Foot%Locker%' or FIELD LIKE '%Foot%Action%' or FIELD LIKE '%Champs%')
In PostgreSQL, I must rewrite each query as such (if I want my query to capture both Foot Locker AND foot locker and any other caps driven permutation):
WHERE (lower(FIELD) LIKE lower('%foot%locker%') or lower(FIELD) LIKE lower('%foot%action%') or lower(FIELD) LIKE lower('%champs%')
This, of course, is very annoying. I have to rewrite 100s of queries. Is there an easy workaround?
Postgres has just what you are looking for ilike:
The key word ILIKE can be used instead of LIKE to make the match
case-insensitive according to the active locale. This is not in the
SQL standard but is a PostgreSQL extension.
(Documented here.)
So, you can do something like:
WHERE (field ILIKE '%foot%locker%' or FIELD ILIKE '%foot%action%' or FIELD) ILIKE '%champs%'
Or, if you prefer:
WHERE lower(field) ~ '(foot.*locker)|(foot.*action)|champ'

In a Rails WHERE LIKE query, what does the percent sign mean?

In a simple search like this:
find.where('name LIKE ?', "%#{search}%")
I understand that #{search} is just string interpolation. What do the % symbols do?
The percent sign % is a wildcard in SQL that matches zero or more characters. Thus, if search is "hello", it would match strings in the database such as "hello", "hello world", "well hello world", etc.
Note that this is a part of SQL and is not specific to Rails/ActiveRecord. The queries it can be used with, and the precise behavior of LIKE, differ based on SQL dialect (MySQL, PostgreSQL, etc.).
search = 'something'
find.where('name LIKE ?', "%#{search}%")
In your DB it will be interpreted as
SELECT <fields> FROM finds WHERE name LIKE '%something%';
The percent sign in a like query is a wildcard. So, your query is saying "anything, followed by whatever is in the search variable, followed by anything".
Note that this use of the percent sign is part of the SQL standard and not specific to Rails or ActiveRecord. Also be aware that this kind of search does note scale well -- your SQL db will be forced to scan through every row in the table trying to find matches rather than being able to rely on an index.

How to cast a MongoDB query and use Index

I have a sql query that I want to convert to MongoDB and still use the index. Here is the sql query
SELECT * FROM "Data1" WHERE age > Cast('12' as int)
According to this SO answer the above query can be converted to:
db.test.find("this.age > 12")
However, using this syntax will not use any indexes. I wanted to know has this issue has been fixed for MonoDB.
You need to use the $gt operator, to make use of indexes.
db.test.find({age:{$gt:12}})
The field age should be indexed.
I wanted to know has this issue has been fixed for MongoDB.
It still can't be achieved.
The doc says, If you need to use java script for evaluation and select documents, you need to use the $where operator. But it would not use the index.
db.test.find( { $where: "this.age>12" } );
From the docs,
$where evaluates JavaScript and cannot take advantage of indexes;
Hence whenever query criteria is evaluated as Java script , it can never make use of indexes.

REGEXP_LIKE in SQLAlchemy

Any one knows how could I use the equivalent of REGEXP_LIKE in SQLAlchemy? For example I'd like to be able to do something like:
sa.Session.query(sa.Table).filter(sa.Table.field.like(regex-to match))
Thanks for your help!
It should (I have no access to Oracle) work like this:
sa.Session.query(sa.Table) \
.filter(sa.func.REGEXP_LIKE(sa.Table.c.column, '[[:digit:]]'))
In cases when you need to do database specific function which is not supported by SQLAlchemy you can use literal filter. So you can still use SQLAlchemy to build query for you - i.e. take care about joins etc.
Here is example how to put together literal filter with PostgreSQL Regex Matching operator ~
session.query(sa.Table).filter("%s ~':regex_pattern'" % sa.Table.c.column.name).params(regex_pattern='stack')
or you can manually specify table and column as a part of literal string to avoid ambigious column names case
session.query(sa.Table).filter("table.column ~':regex_pattern'" ).params(regex_pattern='[123]')
This is not fully portable, but here is a Postgres solution, which uses a ~ operator. We can use arbitrary operators thus:
sa.Session.query(sa.Table).filter(sa.Table.field.op('~', is_comparison=True)(regex-to match))
Or, assuming a default precedence of 0,
sa.Session.query(sa.Table).filter(sa.Table.field.op('~', 0, True)(regex-to match))
This also works with ORM constructs:
sa.Session.query(SomeClass).filter(SomeClass.field.op('~', 0, True)(regex-to match))

How to implement "like" in BigQuery?

I am trying to run a simple query making a restriction of like % in BigQuery, but LIKE is not in their syntax, so how can it be implemented?
You can use the REGEXP_MATCH function (see the query reference page):
REGEXP_MATCH('str', 'reg_exp')
Instead of using the % syntax used by LIKE, you should use regular expressions (detailed syntax definition here)
LIKE is officially supported in BigQuery Standard SQL -
https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#comparison_operators
And I think it also works in Legacy SQL!
REGEXP_MATCH returns true if str matches the regular expression. For string matching without regular expressions, use CONTAINS instead of REGEXP_MATCH.
https://developers.google.com/bigquery/docs/query-reference#stringfunctions
REGEXP_MATCH is great if you know how to use it, but for those who aren't sure there won't be any commonly used special characters such as '.','$' or '?' in the lookup string, you can use LEFT('str', numeric_expr) or RIGHT('str', numeric_expr).
ie if you had a list of names and wanted to return all those that are LIKE 'sa%'
you'd use:
select name from list where LEFT(name,2)='sa'; (with 2 being the length of 'sa')
Additionally, if you wanted to say where one column's values are LIKE another's, you could swap out the 2 for LENGTH(column_with_lookup_strings) and ='sa' for =column_with_lookup_strings, leaving it looking something like this:
select name from list where LEFT(name,LENGTH(column_with_lookup_strings))= column_with_lookup_strings;
https://cloud.google.com/bigquery/query-reference