Hello,
I have a broken query when migrating from SQLAlchemy 0.9.4 to 1.0.12. It
seems to be linked to a behavioral change in the ORM
(http://docs.sqlalchemy.org/en/rel_1_0/changelog/migration_10.html#right-inner-join-nesting-now-the-default-for-joinedload-with-innerjoin-true)
Here is simplified version of the code:
# -*- coding: utf-8 -*-
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
Base = declarative_base()
_plant_table = Table('plant', Base.metadata,
Column('id', Integer, primary_key=True)
)
_plant_dimensionsseries_table = Table('plant_dimensionsseries', Base.
metadata,
Column('plant_id', Integer, primary_key=True),
Column('dimensionsseriestype_id', Integer, primary_key=True),
ForeignKeyConstraint(['plant_id'], ['plant.id'])
)
_view_plant_dimensionsseries_table = Table('view_plant_dimensionsseries',
Base.metadata,
Column('plant_id', Integer, primary_key=True),
Column('dimensionsseriestype_id', Integer, primary_key=True),
ForeignKeyConstraint(
['plant_id', 'dimensionsseriestype_id'],
['plant_dimensionsseries.plant_id',
'plant_dimensionsseries.dimensionsseriestype_id'])
)
class Plant(Base):
__table__ = _plant_table
class PlantDimensionsseries(Base):
__table__ = _plant_dimensionsseries_table
_plant_id = __table__.c.plant_id
_dimensionsseriestype_id = __table__.c.dimensionsseriestype_id
plant = relationship('Plant',
innerjoin=True,
backref=backref('plant_dimensionsseries'))
class PlantDimensionsseriesDataComputed(Base):
__table__ = _view_plant_dimensionsseries_table
_plant_id = __table__.c.plant_id
_dimensionsseriestype_id = __table__.c.dimensionsseriestype_id
# One-to-one relationship
dimensionsseries = relationship('PlantDimensionsseries',
innerjoin=True,
backref=backref('data_computed',
innerjoin=True))
if __name__ == '__main__':
engine = create_engine(
'postgresql://nurseryacme_employee@localhost:5432/nurseryacme')
Session = sessionmaker(bind=engine)
session = Session()
# query 1:
# SQLAlchemy 0.9.4: Correct SQL generated
# SQLAlchemy 1.0.12: Wrong SQL generated, a inner JOIN is used instead
of a LEFT OUTER JOIN between plant_dimensionsseries and
view_plant_dimensionsseries
print session.query(Plant).\
outerjoin(Plant.plant_dimensionsseries).\
options(contains_eager(Plant.plant_dimensionsseries)).\
options(joinedload(Plant.plant_dimensionsseries,
PlantDimensionsseries.data_computed))
# query 2:
# SQLAlchemy 1.0.12: Correct SQL generated
print session.query(Plant).\
outerjoin(Plant.plant_dimensionsseries).\
options(contains_eager(Plant.plant_dimensionsseries)).\
options(joinedload(Plant.plant_dimensionsseries,
PlantDimensionsseries.data_computed, innerjoin=False))
Result with SQLAlchemy 0.9.4:
# query 1
SELECT ...
FROM plant LEFT OUTER JOIN plant_dimensionsseries ON plant.id =
plant_dimensionsseries.plant_id *LEFT OUTER JOIN*
view_plant_dimensionsseries AS view_plant_dimensionsseries_1 ON
plant_dimensionsseries.plant_id = view_plant_dimensionsseries_1.plant_id
AND plant_dimensionsseries.dimensionsseriestype_id =
view_plant_dimensionsseries_1.dimensionsseriestype_id
# query 2
SELECT ...
FROM plant LEFT OUTER JOIN plant_dimensionsseries ON plant.id =
plant_dimensionsseries.plant_id *LEFT OUTER JOIN*
view_plant_dimensionsseries AS view_plant_dimensionsseries_1 ON
plant_dimensionsseries.plant_id = view_plant_dimensionsseries_1.plant_id
AND plant_dimensionsseries.dimensionsseriestype_id =
view_plant_dimensionsseries_1.dimensionsseriestype_id
Result with SQLAlchemy 1.0.12:
# query 1
SELECT ...
FROM plant LEFT OUTER JOIN plant_dimensionsseries ON plant.id =
plant_dimensionsseries.plant_id *JOIN* view_plant_dimensionsseries AS
view_plant_dimensionsseries_1 ON plant_dimensionsseries.plant_id =
view_plant_dimensionsseries_1.plant_id AND
plant_dimensionsseries.dimensionsseriestype_id
= view_plant_dimensionsseries_1.dimensionsseriestype_id
# query 2
SELECT ...
FROM plant LEFT OUTER JOIN plant_dimensionsseries ON plant.id =
plant_dimensionsseries.plant_id *LEFT OUTER JOIN*
view_plant_dimensionsseries AS view_plant_dimensionsseries_1 ON
plant_dimensionsseries.plant_id = view_plant_dimensionsseries_1.plant_id
AND plant_dimensionsseries.dimensionsseriestype_id =
view_plant_dimensionsseries_1.dimensionsseriestype_id
In query 1 under SQLAlchemy 1.0.12, the query discard many rows due the
JOIN chained to the LEFT OUTER JOIN and this precisely what SQLAlchemy
wanted to avoid if I refer to the description of "Right-nested inner joins
available in joined eager loads"
(http://docs.sqlalchemy.org/en/rel_1_0/changelog/migration_09.html#feature-2976).
I can fix the query 1 by adding the innerjoin=False as in query 2 but I am
wondering if this is a bug or the expected behavior following the
behavioral change in SQLAlchemy 1.0.x
(http://docs.sqlalchemy.org/en/rel_1_0/changelog/migration_10.html#right-inner-join-nesting-now-the-default-for-joinedload-with-innerjoin-true).
Is this a bug?
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.