I have run into an interesting condition when using joined table
inheritance. For example we have the typical employee, manager and engineer
tables with the following relationships:
- an engineer is an employee
- a manager is an employee
- an employee has a manager
We find some interesting results when using this query:
session.query(Employee.id, Engineer.id).join(Engineer.manager)
The resulting SQL is:
SELECT employee.id AS employee_id, engineer.id AS engineer_id
FROM engineer, employee JOIN (employee AS employee_1 JOIN manager AS
manager_1 ON manager_1.id = employee_1.id) ON manager_1.id =
employee.manager_id
Notice how the outer engineer and employee tables aren't joined. I would
have expected the engineer and employee from the query() call to be joined.
Example code:
#!/usr/bin/env python
from sqlalchemy import Column, Integer, String, Enum, __version__
from sqlalchemy import ForeignKey
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
print "sqlalchemy version", __version__
engine = create_engine('sqlite:///:memory:', echo=False)
Base = declarative_base()
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String, index=True, nullable=False)
manager_id = Column(
ForeignKey(
'manager.id', use_alter=True, name="manager_id_fkey"
), index=True, nullable=True)
manager = relationship('Manager', foreign_keys=[manager_id])
employee_type = Column(Enum('manager', 'engineer', name='employee_type'
))
__mapper_args__ = {
'polymorphic_identity': __tablename__,
'polymorphic_on': employee_type
}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
__mapper_args__ = {
'polymorphic_identity': __tablename__,
'inherit_condition': id == Employee.id,
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
__mapper_args__ = {
'polymorphic_identity': __tablename__,
'inherit_condition': id == Employee.id,
}
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
Session.configure(bind=engine)
session = Session()
the_boss = Manager(name='the boss')
a_manager = Manager(name='a manager', manager=the_boss)
engineer1 = Engineer(name='engineer 1', manager=a_manager)
engineer2 = Engineer(name='engineer 2', manager=a_manager)
session.add(engineer1)
session.add(engineer2)
session.commit()
def test(test_number, query):
print "\nTest", test_number
print query
print query.count()
test(1, session.query(Engineer.id, Employee.id))
test(2, session.query(Employee.id, Engineer.id))
test(3, session.query(Engineer.id).outerjoin(Engineer.manager))
test(4, session.query(Employee.id).outerjoin(Engineer.manager))
test(5, session.query(Engineer.id, Employee.id).outerjoin(Engineer.manager))
test(6, session.query(Employee.id, Engineer.id).outerjoin(Engineer.manager))
The output
sqlalchemy version 1.0.8
Test 1
SELECT engineer.id AS engineer_id, employee.id AS employee_id
FROM employee JOIN engineer ON engineer.id = employee.id
2
Test 2
SELECT employee.id AS employee_id, engineer.id AS engineer_id
FROM employee JOIN engineer ON engineer.id = employee.id
2
Test 3
SELECT engineer.id AS engineer_id
FROM employee JOIN engineer ON engineer.id = employee.id LEFT OUTER JOIN
(employee
AS employee_1 JOIN manager AS manager_1 ON manager_1.id = employee_1.id) ON
manager_1.id = employee.manager_id
2
Test 4
SELECT employee.id AS employee_id
FROM employee LEFT OUTER JOIN (employee AS employee_1 JOIN manager AS
manager_1 ON manager_1.id = employee_1.id) ON manager_1.id = employee.
manager_id
4
Test 5
SELECT engineer.id AS engineer_id, employee.id AS employee_id
FROM employee JOIN engineer ON engineer.id = employee.id LEFT OUTER JOIN
(employee
AS employee_1 JOIN manager AS manager_1 ON manager_1.id = employee_1.id) ON
manager_1.id = employee.manager_id
2
Test 6
SELECT employee.id AS employee_id, engineer.id AS engineer_id
FROM engineer, employee LEFT OUTER JOIN (employee AS employee_1 JOIN
manager AS manager_1 ON manager_1.id = employee_1.id) ON manager_1.id =
employee.manager_id
8-
This is not an issue, as swapping the columns ends up with the expected
results. However I'd like to understand what's going on.
Thanks for your help
--
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 http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.