我正在尝试将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列。
这些信息用于多种口味......“我是否有新生?我是否仍然拥有特定日期的所有学生?在给定日期之后订阅哪些学生?等等...”此选择的结果语句将保存在另一个数据库中。
我是否有可能通过一个类似视图的课程实现这一目标?信息是只读的,因此我不需要能够修改/创建/删除。或者我必须为每个表声明一个类(最后有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 '*'"
如何使用该查询创建自己可以使用的类?
答案 0 :(得分:3)
如果您可以在数据库上创建此视图,那么您只需将视图映射为表格。请参阅Reflecting Views。
# 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)
答案 1 :(得分: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