Yeah, sorry about that.  Like I said, I don't normally build my classes 
this way, defining all the columns in the Base Class.  I define all my 
columns, primary and foreign keys, etc manually first, so my SQLA classes 
are minimally defined.  And I cobbled together pieces from my real code and 
your example to build that test code I sent you.  So I forgot some things. 
 I did say it may not be completely right, and you might have to hack it 
some.  I apologize.  Here is an attempt at cleaning it up. 

When I try to implement your @expression into my real code, it doesn't 
work.  I am getting an error about multiple results returned within the 
subquery. 

    @restwave.expression
    def restwave(cls):
        s = db.Session()
        restw = (func.unnest(Wavelength.wavelength) / (1 + sampledb.NSA.z)).
label("restw")
        unwave = s.query(restw).select_from(Wavelength).correlate(sampledb.
NSA).subquery("unwave")
        agg_unwave = s.query(func.array_agg(unwave.c.restw)).label(
"restwarr")
        joined = s.query(agg_unwave).select_from(
             Cube
             ).join(sampledb.MangaTarget, sampledb.MangaTargetToNSA, 
sampledb.NSA, Wavelength)
        return joined.as_scalar()

session.query(datadb.Cube.restwave).filter(datadb.Cube.mangaid=='1-113520').
all()

ProgrammingError: (psycopg2.ProgrammingError) more than one row returned by 
a subquery used as an expression
 [SQL: 'SELECT (SELECT (SELECT array_agg(unwave.restw) AS array_agg_1 
\nFROM (SELECT unnest(mangadatadb.wavelength.wavelength) / (%(z_1)s + 
mangasampledb.nsa.z) AS restw \nFROM mangadatadb.wavelength) AS unwave) AS 
restwarr \nFROM mangadatadb.cube JOIN mangasampledb.manga_target ON 
mangasampledb.manga_target.pk = mangadatadb.cube.manga_target_pk JOIN 
mangasampledb.manga_target_to_nsa ON mangasampledb.manga_target.pk = 
mangasampledb.manga_target_to_nsa.manga_target_pk JOIN mangasampledb.nsa ON 
mangasampledb.nsa.pk = mangasampledb.manga_target_to_nsa.nsa_pk JOIN 
mangadatadb.wavelength ON mangadatadb.wavelength.pk = 
mangadatadb.cube.wavelength_pk) AS anon_1 \nFROM mangadatadb.cube \nWHERE 
mangadatadb.cube.mangaid = %(mangaid_1)s'] [parameters: {'z_1': 1, 
'mangaid_1': '1-113520'}]


 I don't know if this is because I have multiple versions of the same 
object or not.  I tried adding in a selection on version, but the joins did 
not work out properly.  This NSA table does not need to be joined with the 
versions.  What I expect the above to return is exactly what the raw SQL 
returns.  A list of the restwave array for each version of the object with 
id = '1-113520'.  I thought SQLA was designed precisely to let users do 
what I'm trying, i.e. construct complex columns involving multiple selects, 
without having to physically add a new column into the db, or write a new 
SQL function in the db to call?  

session.query(datadb.Cube.restwave).join(datadb.Cube,datadb.PipelineInfo,
datadb.PipelineVersion).filter(datadb.PipelineVersion=='v1_5_1',datadb.Cube.
mangaid=='1-113520').all()

InvalidRequestError: Could not find a FROM clause to join from.  Tried 
joining to <class 
'sdss.internal.database.utah.mangadb.DataModelClasses.Cube'>, but got: 
Can't find any foreign key relationships between 'nsa' and 'cube'.


On Wednesday, August 3, 2016 at 2:22:43 PM UTC-4, Mike Bayer wrote:
>
> There is still much ambiguity here and inaccuracy (JOINs on the outside 
> or JOINs on the inside, the mappings have mistakes like foreign key to 
> "pk" but no "pk", mappings without primary keys, "autoload" makes no 
> sense as I don't have your tables, etc.), so I can only guess but 
> perhaps give you enough clues.   It is highly unusual to have a string 
> of four JOINs inside of a column-based subquery, but when you say 
> s.query(Cube.restwave), that's what that means here. 
>
>

-- 
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 https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
import sqlalchemy
from sqlalchemy import ForeignKey, func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, deferred, sessionmaker
from sqlalchemy.schema import Column
from sqlalchemy.dialects.postgresql import *
from sqlalchemy.types import Float, Integer, String
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy import create_engine

# import sqlite3
# conn = sqlite3.connect('/Users/Brian/Work/python/manga/test_sqla.db')
# c = conn.cursor()
# c.execute('''create table cube (pk integer primary key, mangaid text, wavelength_pk integer, target_pk integer);''')
# c.execute('''create table nsa (pk integer primary key, z real);''')
# c.execute('''create table target (pk integer primary key, mangaid text);''')
# c.execute('''create table target_to_nsa (pk integer primary key, target_pk integer, nsa_pk integer);''')
# c.execute('''create table wavelength (pk integer primary key, wavelength real[]);''')
# conn.commit()
# conn.close()

engine = create_engine('sqlite:///test_sqla.db', echo=True)

Base = declarative_base()
Session = sessionmaker(bind=engine)


class Target(Base):
    __tablename__ = 'target'

    pk = Column(Integer, primary_key=True)
    mangaid = Column(String)


class Wavelength(Base):
    __tablename__ = 'wavelength'

    pk = Column(Integer, primary_key=True)
    wavelength = deferred(Column(ARRAY(Float, zero_indexes=True)))

    def __repr__(self):
        return '<Wavelength (pk={0})>'.format(self.pk)


class NSA(Base):
    __tablename__ = 'nsa'

    pk = Column(Integer, primary_key=True)
    z = Column(Float)

    def __repr__(self):
        return '<NSA (pk={0}, nsaid={1})>'.format(self.pk, self.nsaid)


class TargetToNSA(Base):
    __tablename__ = 'target_to_nsa'

    pk = Column(Integer, primary_key=True)
    target_pk = Column(Integer, ForeignKey('target.pk'))
    nsa_pk = Column(Integer, ForeignKey('nsa.pk'))

    def __repr__(self):
        return '<TargetToNSA (pk={0})>'.format(self.pk)

# Relationships
NSA.targets = relationship(Target, backref='NSA_objects', secondary=TargetToNSA.__table__)


class Cube(Base):
    __tablename__ = 'cube'

    pk = Column(Integer, primary_key=True)
    mangaid = Column(String)

    target_pk = Column(Integer, ForeignKey('target.pk'))
    target = relationship(Target, backref='cubes')

    wavelength_pk = Column(Integer, ForeignKey('wavelength.pk'))
    wavelength = relationship(Wavelength, backref='cubes')

    @hybrid_property
    def restwave(self):
        if self.target:
            redshift = self.target.NSA_objects[0].z
            wave = np.array(self.wavelength.wavelength)
            restwave = wave/(1+redshift)
            return restwave
        else:
            return None

    @restwave.expression
    def restwave(cls):
        # session = Session.object_session(self)
        # nsaz = session.query(NSA.z.label('z')).\
        #     join(TargetToNSA, Target, Cube).\
        #     filter(Cube.mangaid == cls.mangaid).subquery('nsaz', with_labels=True)
        # unwave = session.query((func.unnest(Wavelength.wavelength)/(1+nsaz.c.z)).label('restw')).subquery('unwave', with_labels=True)
        # restwave = session.query(func.array_agg(unwave.c.restw)).as_scalar()

        s = Session()
        restw = (func.unnest(Wavelength.wavelength) / (1 + NSA.z)).label("restw")
        unwave = s.query(restw).select_from(Wavelength).correlate(NSA).subquery("unwave")
        agg_unwave = s.query(func.array_agg(unwave.c.restw)).label("restwarr")
        joined = s.query(agg_unwave).select_from(
             Cube
             ).join(Target, TargetToNSA, NSA, Wavelength)
        return joined.as_scalar()


session = Session()

# Add objects
session.begin()
wave = Wavelength(wavelength=[3950.00, 4000.00, 5100.00, 5200.00, 6212.00, 8348.00])
session.add(wave)
nsa = [NSA(z=0.09999543), NSA(z=1.234567), NSA(z=0.0167534563)]
session.add_all(nsa)
targets = [Target(mangaid='1-234567', NSA_objects=nsa[0]),
           Target(mangaid='1-113520', NSA_objects=nsa[2]),
           Target(mangaid='1-367842', NSA_objects=nsa[1])]
session.add_all(targets)
session.flush()
cubes = [Cube(wavelength=wave, mangaid='1-987345'),
         Cube(wavelength=wave, mangaid='1-234567', target=targets[0]),
         Cube(wavelength=wave, mangaid='1-367842', target=targets[2]),
         Cube(wavelength=wave, mangaid='1-113520', target=targets[1])]
session.commit()


q = session.query(Cube.restwave).filter(Cube.mangaid == '1-113520')

print q



Reply via email to