145

How do I combine two columns and apply filter? For example, I want to search in both the "firstname" and "lastname" columns at the same time. Here is how I have been doing it if searching only one column:

query = meta.Session.query(User).filter(User.firstname.like(searchVar))
3
  • 5
    I thought that this question matched the issue that I have, but the answers don't apply to my particular scenario. If firstname is "joe" and lastname is "smith", I'm looking for a filter statement that will match when the supplied searchVar is "joe smith". I.e., the fields need to be concatenated (with space added) before the test is made. Seems like a very real-world scenario. Commented May 13, 2015 at 15:12
  • 2
    @Groovee60 This is exactly what I am looking for. I would appreciate it if you'd be able to share your solution, if you found one. Commented May 30, 2017 at 11:17
  • Anyone looking for a solution to the problem @Groovee60 mentioned 7 years ago can now use Mapped attributes Commented Jul 30, 2022 at 1:03

5 Answers 5

191

There are number of ways to do it:

Using filter() (and operator)

query = meta.Session.query(User).filter(
    User.firstname.like(search_var1),
    User.lastname.like(search_var2)
    )

Using filter_by() (and operator)

query = meta.Session.query(User).filter_by(
    firstname.like(search_var1),
    lastname.like(search_var2)
    )

Chaining filter() or filter_by() (and operator)

query = meta.Session.query(User).\
    filter_by(firstname.like(search_var1)).\
    filter_by(lastname.like(search_var2))

Using or_(), and_(), and not()

from sqlalchemy import and_, or_, not_

query = meta.Session.query(User).filter(
    and_(
        User.firstname.like(search_var1),
        User.lastname.like(search_var2)
    )
)
Sign up to request clarification or add additional context in comments.

5 Comments

Are there any noteworthy performance differences for these different approaches?
Most of the different approaches will end up generating the same query, so in most cases you won't see a performance difference.
I'm a bit confused. The filter_by docs say that it's for filtering by keyword argument: query(Foo).filter_by(bar='baz'). How does that relate to the syntax you used in your answer above?
filter_by takes only one argument
Why would one use one approach over another?
94

You can simply call filter multiple times:

query = meta.Session.query(User).filter(User.firstname.like(searchVar1)). \
                                 filter(User.lastname.like(searchVar2))

3 Comments

is there any performance-difference between using multiple filter() methods and using the combination of multiple conditions (by or_ or and_) in a single filter, on large mysql tables?
Would multiple filter calls act like a logical AND rather than an OR ?
I wouldnt think so - when you look at str(User.filter(cond1).filter(cond2)) generates the final sql with just the conditions "and"ed.
76

You can use SQLAlchemy's or_ function to search in more than one column (the underscore is necessary to distinguish it from Python's own or).

Here's an example:

from sqlalchemy import or_
query = meta.Session.query(User).filter(or_(User.firstname.like(searchVar),
                                            User.lastname.like(searchVar)))

4 Comments

You can use | operator instead of or_, like this - (User.firstname.like(searchVar)) | (User.lastname.like(searchVar)), however you should be careful with | precedence, without parenthesis it can produce VERY unexpected results when mixed with comparsion operators.
Shouldn't it be filter.or_( case1, case 2)?
This is wrong, as question is about ORM but link leads to expressions.
I was using multiple filter statements before which increased latency dramatically. I changed it to the or_ and it's returning MUCH faster. Thank you @gclj5
6

A generic piece of code that will work for multiple columns. This can also be used if there is a need to conditionally implement search functionality in the application.

search_key = 'abc'
search_args = [col.ilike('%%%s%%' % search_key) for col in ['col1', 'col2', 'col3']]
query = Query(table).filter(or_(*search_args))
session.execute(query).fetchall()

Note: the %% are important to skip % formatting the query.

2 Comments

Ahh, not that this was really the question, but this is actually what i was looking for! +1
I use alchemy orm and got 'str object has no attribute error'
1

To make the filter work for the full name, you can modify the query to use the concat function provided by the database engine. Here's an example of how you can update your code to make it work:

from sqlalchemy import func

query = meta.Session.query(User).filter(func.concat(User.firstname, ' ', User.lastname).contains(searchVar))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.