HOW TO DO OBJECT RELATIONAL MAPPING(ORM) FOR THIS QUERY? - python

I am trying to convert my sql query into python code by using flask-SQLAlchemy.
I am stuck at one query.
there are tables name flights and passengers where flight_id(passengers) is foreign key and id(flights) is Primary key.
My sql-query is:
SELECT * FROM flights JOIN
passengers ON flights.id=passengers.flight_id;
please help me converting it in python

try this:
db.session.query(flights,passengers).filter
(flights.id==passenger.flight_id).all()

Assuming your models look something like these (this is pure sqlalchemy, rather than flask-sqlalchemy):
import sqlalchemy as sa
from sqlalchemy import orm
class Flight(Base):
__tablename__ = 'flights'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(64))
passengers = orm.relationship('Passenger', back_populates='flight')
class Passenger(Base):
__tablename__ = 'passengers'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(64))
flight_id = sa.Column(sa.Integer, sa.ForeignKey('flights.id'))
flight = orm.relationship('Flight', back_populates='passengers')
then this query:
session.query(Flight).join(Passenger)
will generate this SQL when executed:
SELECT flights.id AS flights_id, flights.name AS flights_name
FROM flights JOIN passengers ON flights.id = passengers.flight_id
and will return all the flight objects which have at least one passenger.
By contrast, this query:
session.query(Flight, Passenger).filter(Flight.id == Passenger.flight_id)
generates this SQL:
SELECT flights.id AS flights_id, flights.name AS flights_name, passengers.id AS passengers_id, passengers.name AS passengers_name, passengers.flight_id AS passengers_flight_id
FROM flights, passengers
WHERE flights.id = passengers.flight_id
which returns a (Flight, Passenger) tuple for each passenger that has a flight.
See the Sqlalchemy ORM tutorial for creating relationships and querying with joins.

Related

SQLAlchemy: fill object with stored procedure or more complicated sql statement

I have an sql alchemy class that I use called Feature.
class Feature(DBConnect.Base):
__tablename__ = 'feature'
id = Column(Integer, primary_key=True)
name = Column(String(500), nullable=False, default='')
In other code I can get a feature by doing:
feature = db.session.query(Feature).get(10)
And I end up with a feature object. Is there away to do a stored procedure or more complicated query like so:
select * from feature f
join aligned_data_column a on a.id=f.aligned_Data_column_id and
a.aligned_data_id=76
where a.aligned_data_id=70
union
select * from feature f
join aligned_data_column a on a.aligned_data_id=76
where json_contains(json_extract(f.column_mappings, '$.*'),CAST(a.id as JSON))
I was hoping to be able to just input that query into a stored procedure or some where in code. I am using MySQL and python 3.x

sqlalchemy: Select from table where column in QUERY

I have a situation where I am trying to count up the number of rows in a table when the column value is in a subquery. For example, lets say that I have some sql like so:
select count(*) from table1
where column1 in (select column2 from table2);
I have my tables defined like so:
class table1(Base):
__tablename__ = "table1"
__table_args__ = {'schema': 'myschema'}
acct_id = Column(DECIMAL(precision=15), primary_key=True)
class table2(Base):
__tablename__ = "table2"
__table_args__ = {'schema': 'myschema'}
ban = Column(String(length=128), primary_key=True)
The tables are reflected from the database so there are other attributes present that aren't explicitly specified in the class definition.
I can try to write my query but here is where I am getting stuck...
qry=self.session.query(func.?(...)) # what to put here?
res = qry.one()
I tried looking through the documentation here but I don't see any comparable implementation to the 'in' keyword which is a feature of many SQL dialects.
I am using Teradata as my backend if that matters.
sub_stmt = session.query(table2.some_id)
stmt = session.query(table1).filter(table1.id.in_(sub_stmt))
data = stmt.all()

SQL to SQLAlchemy translation

I have a, somewhat odd, query that gets me all the items in a parent table that have no matches in its corresponding child table.
If possible, id like to turn it into an SQLAlchemy query. But I have no idea how. I can do basic gets and filters, but this one is beyond my experience so far. Any help you folks might give would be greatly appreciated.
class customerTranslations(Base):
"""parent table. holds customer names"""
__tablename__ = 'customer_translation'
id = Column(Integer, primary_key=True)
class customerEmails(Base):
"""child table. hold emails for customers in translation table"""
__tablename__ = 'customer_emails'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('customer_translation.id'))
I want to build:
SELECT * FROM customer_translation
WHERE id NOT IN (SELECT parent_id FROM customer_emails)
You have a subquery, so create one first:
all_emails_stmnt = session.query(customerEmails.parent_id).subquery()
and then you can use that to filter your other table:
translations_with_no_email = session.query(customerTranslations).filter(
~customerTranslations.id.in_(all_emails_stmnt))
This produces the same SQL (but with all the column names expanded, rather than using *, the ORM then can create your objects):
>>> all_emails_stmnt = session.query(customerEmails.parent_id).subquery()
>>> print(all_emails_stmnt)
SELECT customer_emails.parent_id
FROM customer_emails
>>> translations_with_no_email = session.query(customerTranslations).filter(
... ~customerTranslations.id.in_(all_emails_stmnt))
>>> print(translations_with_no_email)
SELECT customer_translation.id AS customer_translation_id
FROM customer_translation
WHERE customer_translation.id NOT IN (SELECT customer_emails.parent_id
FROM customer_emails)
You could also use NOT EXISTS:
from sqlalchemy.sql import exists
has_no_email_stmnt = ~exists().where(customerTranslations.id == customerEmails.parent_id)
translations_with_no_email = session.query(customerTranslations).filter(has_no_email_stmnt)
or, if you have a a backreference on the customerTranslations class pointing to emails, named emails, use .any() on the relationship and invert:
session.query(customerTranslations).filter(
~customerTranslations.emails.any())
Back in 2010 NOT EXISTS was a little slower on MySQL but you may want to re-assess if that is still the case.

How to calculate ST_Union with GeoAlchemy2?

I have a many-to-many relationship, with instances of OsmAdminUnit (polygon geometries) grouped into OsmAdminAgg instances.
The model definitions are essentially:
class OsmAdminUnit(db.Model):
__tablename__ = 'osm_admin'
id = db.Column(db.Integer, primary_key=True)
geometry = db.Column(Geometry(
geometry_type='GEOMETRY',
srid=3857), nullable=False)
agg_units = db.relationship('OsmAdminAgg',
secondary=aggregations,
backref=db.backref('osm_admin', lazy='dynamic'))
class OsmAdminAgg(db.Model):
__tablename__ = 'admin_agg'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True, nullable=False)
Now what I am struggling to do is selecting OsmAdminUnits that belong to a certain OsmAdminAgg AND getting the polgyons merged by applying ST_Union from GeoAlchemy.
Selecting all admin units that belong to admin agg with id=1 works:
units = OsmAdminUnit.query.filter(OsmAdminUnit.agg_units.any(id=1)).all()
But I don't get how I can apply ST_Union on that result.
My approach so far was:
union = db.session.query(
OsmAdminUnit.geometry.ST_Union().ST_AsGeoJSON().label('agg_union')
).filter(OsmAdminUnit.agg_units.any(id=1)).subquery()
So how do I get the union of these geometries, and get it as GeoJSON?
Btw, I am building this on top of Flask, using SQLAlchemy, Flask-SQLAlchemy, Geoalchemy2.
Try this:
from sqlalchemy.sql.functions import func
union = db.session.query(func.ST_AsGeoJSON(func.ST_Union(
OsmAdminUnit.geometry)).label('agg_union')
).filter(OsmAdminUnit.agg_units.any(id=1)).subquery()
You can see a basic template for this in the GeoAlchemy 2 docs. Essentially, you need to pass func to the query, rather than the model, to select the union itself.
In your case, something like:
import sqlalchemy
union = db.session.query(
sqlalchemy.func.ST_AsGeoJSON(
sqlalchemy.func.ST_Union(OsmAdminUnit.geometry)
).label('agg_union')
).filter(
OsmAdminUnit.agg_units.any(id=1)
).all()
This grabs the union of geometry values for OsmAdminUnit records matching the filter, and returns it as stringified GeoJSON.
The accepted answer didn't work for me, I think the import may be different in the version of sqlalchemy I'm using.

SQLAlchemy query for object with count of relationship

Lets say I have SQL Alchemy ORM classes:
class Session(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_agent = db.Column(db.Text, nullable=False)
class Run(db.Model):
id = db.Column(db.Integer, primary_key=True)
session_id = db.Column(db.Integer, db.ForeignKey('session.id'))
session = db.relationship('Session', backref=db.backref('runs', lazy='dynamic'))
And I want to query for essentially the following:
((session.id, session.user_agent, session.runs.count())
for session in Session.query.order_by(Session.id.desc()))
However, this is clearly 1+n queries, which is terrible. What is the correct way to do this, with 1 query? In normal SQL, I would do this with something along the lines of:
SELECT session.id, session.user_agent, COUNT(row.id) FROM session
LEFT JOIN rows on session.id = rows.session_id
GROUP BY session.id ORDER BY session.id DESC
Construct a subquery that groups and counts session ids from runs, and join to that in your final query.
sq = session.query(Run.session_id, func.count(Run.session_id).label('count')).group_by(Run.session_id).subquery()
result = session.query(Session, sq.c.count).join(sq, sq.c.session_id == Session.id).all()
The targeted SQL could be produced simply with:
db.session.query(Session, func.count(Run.id)).\
outerjoin(Run).\
group_by(Session.id).\
order_by(Session.id.desc())

Categories

Resources