I have some sql queries I'm trying to run as sqlalchemy.orm.query objects and I'm wondering if there is a way to use OR. I can use AND by adding commas into the filter statement but I don't know how to do an OR. Example code below:
query = MyTable.q.filter(MyTable.id == some_number)
However I don't know how to do a query with an OR
query = MyTable.q.filter(MyTable.id == some_number OR MyTable.id == some_other_number)
Any help is greatly appreciated
from sqlalchemy.sql import or_
query = MyTable.q.filter(
or_(MyTable.id == some_number, MyTable.id == some_other_number)
)
Of course, there's no point in this case since you can solve it with in_.
query = MyTable.q.filter(MyTable.id.in_([some_number, some_other_number])
Related
I'm trying to replicate this raw sql into proper sqlalchemy implementation but after a lot of tries I can't find a proper way to do it:
SELECT *
FROM images i
WHERE NOT EXISTS (
SELECT image_id
FROM events e
WHERE e.image_id=i.id AND e.chat_id=:chat_id)
ORDER BY random()
LIMIT 1
Closest I got is:
session.query(Image).filter(and_(Event.image_id == Image.id, Event.chat_id == chat_id)).order_by(func.random()).limit(1)
But I cant seem to find how to put the NOT EXISTS clause.
Can anyone lend a helping hand?
Thanks!
You're querying the FROM images table, but the WHERE clause is a subquery, not e.image_id=i.id AND e.chat_id=:chat_id (these filters are for events instead). So, the correct query is of the form
session.query(Image).filter(subquery).order_by(func.random()).limit(1)
The way to form an EXISTS subquery is with the .exists() method, so to get NOT EXISTS just use the ~ operator:
subquery = ~session.query(Event).filter(Event.image_id == Image.id, Event.chat_id == chat_id).exists()
Note that the emitted query is not identical to your original (e.g. it uses EXISTS (SELECT 1 ...)), but it's functionally the same.
Beginning of my raw sql statement looks like this:
select if(substr(Table.order_id,1,8)='STRING', Table1.name, t=Table2.type)
Tried to rewrite it in SQLAlchemy query:
query = db_session.query(Table,\
Table1.name if Table.order_id[1:8] == 'STRING' else Table2.type)
But it returned Operator 'getitem' is not supported on this expression.
How can I add this condition to my ORM query without touching models?
Or how can I add raw sql statement in query parameters?
PS: I would prefer not to make any changes to models.
You need to use Functions:
from sqlalchemy import func
q = db_session.query(
func.IF(func.substr(Table.order_id, 1, 8) == 'STRING', Table1.name, Table2.type)
)
I'm relatively new to SQLAlchemy, and thus far have not had to do anything that complex. I now have a need to return the latest "version" of a row. I can use "distinct" to return the relevant list, however I'm struggling to have the query return SQLAlchemy models.
session.query(Document.document_id,func.max(Document.id)).\
filter_by(container_id=1,active=True).\
group_by(Document.document_id).all()
This returns the list of ids that I need. But what I really need is the whole model.
I'm sure there's a simple way to join it. However it has completely eluded me.
Using a subquery, you can than join:
subq = (session.query(
# Document.document_id, # do not need this really
func.max(Document.id).label("max_id")
)
.filter(Document.container_id == 1)
.filter(Document.active == True)
.group_by(Document.document_id)
).subquery("subq")
qry = (session.query(Document)
.join(subq, Document.id == subq.c.max_id)
).all()
I am learning to use SQL alchemy to connect to a mysql database. I want to pull records from the DB that start with a given string. I know that for simple equality all I need to do is this
queryRes = ses.query(Table).filter(Table.fullFilePath == filePath).all()
result = []
How do I do something like this?
queryRes = ses.query(Table).filter(Table.fullFilePath.startsWith(filePath)).all()
result = []
Maybe the query would look like this?
q = ses.query(Table).filter(Table.fullFilePath.like('path%')).all()
SQLAlchemy has a startswith column property, so it works exactly as you'd think:
queryRes = ses.query(Table).filter(Table.fullFilePath.startswith(filePath)).all()
This is the pure SQL:
SELECT * FROM table WHERE field LIKE "string%"
The SQL alchemy is:
q = ses.query(Table).filter(Table.fullFilePath.like('path%')).all()
If you need a case insensitive comparison, use ilike:
session.query(SomeTable).filter(SomeTable.some_column.ilike('bla%')).all()
The following code is database specific:
import sqlalchemy
# ...
ergebnis = session.query(
my_object.attr1).filter(sa.and_(
my_object.attr2 != 'NaN')).all() # PostgreSQL
"""
my_object.attr2 != None)).all() # sQLite
"""
With PostgreSQL it is "'NaN'", with SQLite "None" (without single quotes). Is there an SQLAlchemy way to do this backend independent?
If you want to compare against the 'NaN' ("not a number") float value, then do an explicit cast to float: float('NaN'). In this case SQLAlchemy should do the same conversion.
This seems to work for Postgres, but I don't know how database-independent it is:
import sqlalchemy as sqla
...
myobject.attr2 != sqla.cast(float("NaN"), sqla.Float)