Hello again. I have successfully installed SA 0.7.10 and the query as-is works. However jonedload_all / subqueryload_all options on the query do NOT work. I have slightly extended your cte_example which now demonstrates the issues. joinedload_all does not crash but there is undesired sql activity after the main query which renders the joinedload useless. subqueryload_all crashes.
I would be glad for any words of advice or idea(s) for possible workaround(s), Ladislav Lenart On 28.2.2013 10:26, Ladislav Lenart wrote: > Thank you very much for your valuable time, Michael! > > Your example code seems correct. The only differences I found are: > * Missing FK on ImportedPartnerShare.partner_id: > class ImportedPartnerShare(Base): > deal_id = Column(Integer, ForeignKey('deal.id')) > partner_id = Column(Integer, ForeignKey('partner.id')) # ForeignKey() is > missing in yout example script > * All FKs in the example should have nullable=False and ondelete='CASCADE'. > > But I suppose none of this makes any difference. As you wrote and confirmed, > this issue (and many others) was resolved in SA 0.7.9. I have just verified > that > I am using SA 0.7.8 at the moment (version from debian distro). I apologize > for > the err subject. I did not check it when I wrote that line, I just assumed. > > > Thank you again, > > Ladislav Lenart > > > On 28.2.2013 04:12, Michael Bayer wrote: >> OK, I've reconstructed mappings which correspond directly to your Query as >> given, and it produces the identical SQL. I've inserted a bunch of rows >> into all the tables so that a polymorphic result comes back, so that we can >> in fact verify that the ORM reads the "client_id" column correctly. >> >> Your issue exists from SQLAlchemy 0.7.8 and backwards, and was fixed as of >> 0.7.9, (we're up to 0.7.10 as well as 0.8 betas). 0.7.9 had many bug fixes >> for the CTE feature as it had only been introduced in 0.7.6. >> >> Script is attached. >> >> >> On Feb 27, 2013, at 4:11 PM, Michael Bayer <mike...@zzzcomputing.com> wrote: >> >>> >>> On Feb 27, 2013, at 3:12 PM, Ladislav Lenart <lenart...@volny.cz> wrote: >>> >>>> Hello. >>>> >>>> Thank you for your prompt answer. I will try to create a working example >>>> that >>>> demonstrates the issue. Though it will take me a couple of days, maybe >>>> weeks (my >>>> regular work followed by a vacation). >>>> >>>> I have another problem. I rephrased the SQL, because postgres's planner had >>>> issues with EXISTS and thought it is a great idea to perform full scans of >>>> several huge tables in order to return several hundreds result rows. Enter >>>> CTEs... >>>> >>>> Short-short intro: >>>> * Client is the joined table inheritance root. >>>> * PersonalClient and CorporateClient are its subclasses. >>>> * Partner is a salesman. >>>> * Deal is a contract signed between salesman(s) and client(s). >>>> * ImportedClientShare and ClientShare are M:N relationships between >>>> clients and >>>> deals. >>>> * ImportedPartnerShare and PartnerShare are M:N relationships between >>>> partners >>>> and deals. >>>> * We import deals from an external DB. Those are called imported. Imported >>>> deal >>>> has external_id and Imported*Share apply. >>>> * However, a user of our system (a partner) can create a new deal locally. >>>> Such >>>> a deal does not have an external id (yet) and local *Share apply to it. >>>> >>>> The following code should return all clients of a given partner via >>>> ImportedClientShare or via ClientShare: >>>> >>>> q1 = session.query(ImportedClientShare.client_id.label('client_id')) >>>> q1 = q1.join(ImportedPartnerShare, ImportedClientShare.deal_id == >>>> ImportedPartnerShare.deal_id) >>>> q1 = q1.join(Deal, ImportedClientShare.deal_id == Deal.id) >>>> q1 = q1.filter( >>>> ImportedPartnerShare.partner_id == partner_id, # input argument >>>> Deal.external_id != None, >>>> ) >>>> q2 = session.query(ClientShare.client_id.label('client_id')) >>>> q2 = q2.join(PartnerShare, ClientShare.deal_id == >>>> PartnerShare.deal_id) >>>> q2 = q2.join(Deal, ClientShare.deal_id == Deal.id) >>>> q2 = q2.filter( >>>> PartnerShare.partner_id == partner_id, # input argument >>>> Deal.external_id == None, >>>> ) >>>> client_ids = q1.union(q2).cte('client_ids') >>>> q = session.query(Client).with_polymorphic([PersonalClient, >>>> CorporateClient]) >>>> q = q.join(client_ids, Client.id == client_ids.c.client_id) >>>> >>>> NoSuchColumnError: "Could not locate column in row for column 'client.id'" >>>> >>>> I also tried it without with_polymorphic() and the result is the same. >>>> >>>> Do you have any idea what is going on / what am I doing wrong and how I >>>> can fix >>>> this? >>> >>> Again, this is a very complex query, even more complex than the previous >>> one, and it boils down to limits in what the ORM can currently handle. >>> It's probably a bug, though there may be workarounds that allow it to work, >>> however it's the kind of issue that typically takes me many hours to >>> diagnose and fix or at least work around, given code that I can run and pdb >>> in order to debug. This is not something you'd have much luck resolving on >>> your own unless you wanted to become deeply familiar with SQLAlchemy >>> internals. >>> >>> I would recommend again making sure all these issues remain in the latest >>> 0.8 version and attempting to produce a rudimentary series of test classes >>> which I can run in order to reproduce your results. I can reconstitute >>> these models looking just at your queries, though sometimes after all that >>> effort the issue isn't reproduced, due to some quirk in the mappings that's >>> also required. >>> >>> -- >>> 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 sqlalchemy+unsubscr...@googlegroups.com. >>> To post to this group, send email to sqlalchemy@googlegroups.com. >>> Visit this group at http://groups.google.com/group/sqlalchemy?hl=en. >>> For more options, visit https://groups.google.com/groups/opt_out. -- 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 sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy?hl=en. For more options, visit https://groups.google.com/groups/opt_out.
from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.declarative import declarative_base, declared_attr import re class Base(object): @declared_attr def __tablename__(cls): name = cls.__name__ return ( name[0].lower() + re.sub(r'([A-Z])', lambda m: "_" + m.group(0).lower(), name[1:]) ) id = Column(Integer, primary_key=True) Base = declarative_base(cls=Base) class ImportedClientShare(Base): deal_id = Column(Integer, ForeignKey('deal.id'), nullable=False) client_id = Column(Integer, ForeignKey('client.id'), nullable=False) class ImportedPartnerShare(Base): deal_id = Column(Integer, ForeignKey('deal.id'), nullable=False) partner_id = Column(Integer) class Deal(Base): external_id = Column(Integer) class PartnerShare(Base): deal_id = Column(Integer, ForeignKey('deal.id'), nullable=False) partner_id = Column(Integer) class ClientShare(Base): deal_id = Column(Integer, ForeignKey('deal.id'), nullable=False) client_id = Column(Integer, ForeignKey('client.id'), nullable=False) class Client(Base): type = Column(String(50)) external_id = Column(Integer) __mapper_args__ = { 'polymorphic_on': type, 'polymorphic_identity': 'client' } class PersonalClient(Client): id = Column(Integer, ForeignKey('client.id'), primary_key=True) data_id = Column(Integer, ForeignKey('personal_data.id'), nullable=False) data = relationship('PersonalData', uselist=False) __mapper_args__ = { 'polymorphic_identity': 'personal' } class CorporateClient(Client): id = Column(Integer, ForeignKey('client.id'), primary_key=True) data_id = Column(Integer, ForeignKey('corporate_data.id'), nullable=False) data = relationship('CorporateData', uselist=False) __mapper_args__ = { 'polymorphic_identity': 'corporate' } class PersonalData(Base): address_id = Column(Integer, ForeignKey('address.id'), nullable=False) address = relationship('Address', uselist=False) class CorporateData(Base): address_id = Column(Integer, ForeignKey('address.id'), nullable=False) address = relationship('Address', uselist=False) class Address(Base): pass engine = create_engine("postgresql://lada:heslo@localhost:5433/sandbox", echo='debug') Base.metadata.drop_all(engine) Base.metadata.create_all(engine) session = Session(engine) partner_id = 610566 session.add_all([ Deal(id=1), Deal(id=2, external_id=10), Address(id=1), Address(id=2), PersonalData(id=1, address_id=1), CorporateData(id=1, address_id=2), PersonalClient(id=1, data_id=1), CorporateClient(id=2, data_id=1), ]) session.flush() session.add_all([ ClientShare(id=1, deal_id=1, client_id=1), ImportedClientShare(id=1, deal_id=2, client_id=1), PartnerShare(id=1, deal_id=1, partner_id=partner_id), ImportedPartnerShare(id=1, deal_id=2, partner_id=partner_id), ]) session.commit() q1 = session.query(ImportedClientShare.client_id.label('client_id')) q1 = q1.join(ImportedPartnerShare, ImportedClientShare.deal_id == ImportedPartnerShare.deal_id) q1 = q1.join(Deal, ImportedClientShare.deal_id == Deal.id) q1 = q1.filter( ImportedPartnerShare.partner_id == partner_id, Deal.external_id != None, ) q2 = session.query(ClientShare.client_id.label('client_id')) q2 = q2.join(PartnerShare, ClientShare.deal_id == PartnerShare.deal_id) q2 = q2.join(Deal, ClientShare.deal_id == Deal.id) q2 = q2.filter( PartnerShare.partner_id == partner_id, Deal.external_id == None, ) client_ids = q1.union(q2).cte('client_ids') q = session.query(Client).with_polymorphic([PersonalClient, CorporateClient]) q = q.join(client_ids, Client.id == client_ids.c.client_id) #q = q.options( # joinedload_all(PersonalClient.data, PersonalData.address), # joinedload_all(CorporateClient.data, CorporateData.address), #) q = q.options( subqueryload_all(PersonalClient.data, PersonalData.address), subqueryload_all(CorporateClient.data, CorporateData.address), ) r = q.all() print "XXXXXXXXXXX" print r[0].data.address