1

我正在尝试使 MySQLdb 应用程序的某些部分适应声明性基础中的 sqlalchemy。我只是从 sqlalchemy 开始。

遗留表的定义如下:

student: id_number*, semester*, stateid, condition, ...
choice: id_number*, semester*, choice_id, school, program, ...

我们每个人都有 3 个表(student_tmp, student_year, student_summer, choice_tmp, choice_year, choice_summer),所以每对(_tmp, _year, _summer)都包含特定时刻的信息。

select *
from `student_tmp`
    inner join `choice_tmp` using (`id_number`, `semester`)

我的问题是对我来说重要的信息是获得与以下选择等效的信息:

SELECT t.*
FROM (
        (
            SELECT st.*, ct.*
            FROM `student_tmp` AS st
                INNER JOIN `choice_tmp` as ct USING (`id_number`, `semester`)
            WHERE (ct.`choice_id` = IF(right(ct.`semester`, 1)='1', '3', '4'))
                AND (st.`condition` = 'A')
        ) UNION (
            SELECT sy.*, cy.*
            FROM `student_year` AS sy
                INNER JOIN `choice_year` as cy USING (`id_number`, `semester`)
            WHERE (cy.`choice_id` = 4)
                AND (sy.`condition` = 'A')
        ) UNION (
            SELECT ss.*, cs.*
            FROM `student_summer` AS ss
                INNER JOIN `choice_summer` as cs USING (`id_number`, `semester`)
            WHERE (cs.`choice_id` = 3)
                AND (ss.`condition` = 'A')
        )
    ) as t

*用于缩短选择,但实际上我只查询 50 个可用列中的大约 7 列。

此信息有多种用途......“我有新学生吗?我还有给定日期的所有学生吗?在给定日期之后订阅了哪些学生?等等......”这个 select 语句的结果是保存在另一个数据库中。

我有可能通过一个类似视图的类来实现这一点吗?该信息是只读的,因此我不需要能够修改/创建/删除。还是我必须为每个表声明一个类(最终有 6 个类)并且每次我需要查询时,我必须记住过滤?

感谢指点。

编辑:我没有对数据库的修改访问权限(我无法创建视图)。两个数据库可能不在同一台服务器上(因此我无法在第二个数据库上创建视图)。

condition我担心的是在过滤和之前避免全表扫描choice_id

编辑 2:我已经设置了这样的声明性类:

class BaseStudent(object):
    id_number = sqlalchemy.Column(sqlalchemy.String(7), primary_key=True)
    semester = sqlalchemy.Column(sqlalchemy.String(5), primary_key=True)
    unique_id_number = sqlalchemy.Column(sqlalchemy.String(7))
    stateid = sqlalchemy.Column(sqlalchemy.String(12))
    condition = sqlalchemy.Column(sqlalchemy.String(3))

class Student(BaseStudent, Base):
    __tablename__ = 'student'

    choices = orm.relationship('Choice', backref='student')

#class StudentYear(BaseStudent, Base):...
#class StudentSummer(BaseStudent, Base):...

class BaseChoice(object):
    id_number = sqlalchemy.Column(sqlalchemy.String(7), primary_key=True)
    semester = sqlalchemy.Column(sqlalchemy.String(5), primary_key=True)
    choice_id = sqlalchemy.Column(sqlalchemy.String(1))
    school = sqlalchemy.Column(sqlalchemy.String(2))
    program = sqlalchemy.Column(sqlalchemy.String(5))


class Choice(BaseChoice, Base):
    __tablename__ = 'choice'

    __table_args__ = (
            sqlalchemy.ForeignKeyConstraint(['id_number', 'semester',],
                [Student.id_number, Student.semester,]),
            )

#class ChoiceYear(BaseChoice, Base): ...
#class ChoiceSummer(BaseChoice, Base): ...

现在,为一组表提供正确 SQL 的查询是:

q = session.query(StudentYear, ChoiceYear) \
            .select_from(StudentYear) \
            .join(ChoiceYear) \
            .filter(StudentYear.condition=='A') \
            .filter(ChoiceYear.choice_id=='4')

但它抛出一个异常......

"Could not locate column in row for column '%s'" % key)
sqlalchemy.exc.NoSuchColumnError: "Could not locate column in row for column '*'"

如何使用该查询为自己创建一个可以使用的类?

4

2 回答 2

3

如果您可以在数据库上创建此视图,那么您只需将视图映射为表即可。请参阅反射视图

# DB VIEW
CREATE VIEW my_view AS -- @todo: your select statements here

# SA
my_view = Table('my_view', metadata, autoload=True)
# define view object
class ViewObject(object):
    def __repr__(self):
        return "ViewObject %s" % str((self.id_number, self.semester,))
# map the view to the object
view_mapper = mapper(ViewObject, my_view)

# query the view
q = session.query(ViewObject)
for _ in q:
    print _

如果您无法VIEW在数据库级别创建一个,您可以创建一个可选择的并将其映射ViewObject到它。下面的代码应该给你的想法:

student_tmp = Table('student_tmp', metadata, autoload=True)
choice_tmp = Table('choice_tmp', metadata, autoload=True)
# your SELECT part with the columns you need
qry = select([student_tmp.c.id_number, student_tmp.c.semester, student_tmp.stateid, choice_tmp.school])
# your INNER JOIN condition
qry = qry.where(student_tmp.c.id_number == choice_tmp.c.id_number).where(student_tmp.c.semester == choice_tmp.c.semester)
# other WHERE clauses
qry = qry.where(student_tmp.c.condition == 'A')

您可以像这样创建 3 个查询,然后将它们与union_all组合并在映射器中使用生成的查询:

view_mapper = mapper(ViewObject, my_combined_qry)

在这两种情况下,您都必须确保在视图上正确定义了 PrimaryKey,并且您可能需要override自动加载视图,并明确指定主键(参见上面的链接)。否则,您将收到错误,或者可能无法从查询中获得正确的结果。


对 EDIT-2 的回答:

qry = (session.query(StudentYear, ChoiceYear).
        select_from(StudentYear).
        join(ChoiceYear).
        filter(StudentYear.condition == 'A').
        filter(ChoiceYear.choice_id == '4')
        )

结果将是元组对:(Student, Choice).
但是如果你想为查询创建一个新的映射类,那么你可以像上面的示例一样创建一个可选择的类:

student_tmp = StudentTmp.__table__
choice_tmp = ChoiceTmp.__table__
.... (see sample code above)
于 2012-05-23T22:27:23.080 回答
1

这是为了展示我最终做了什么,欢迎任何评论。


class JoinedYear(Base):
    __table__ = sqlalchemy.select(
            [
                StudentYear.id_number,
                StudentYear.semester,
                StudentYear.stateid,
                ChoiceYear.school,
                ChoiceYear.program,
                ],
                from_obj=StudentYear.__table__.join(ChoiceYear.__table__),
                ) \
                .where(StudentYear.condition == 'A') \
                .where(ChoiceYear.choice_id == '4') \
                .alias('YearView')

我会从那里详细说明...

谢谢@van

于 2012-05-26T06:16:07.487 回答