1

MySQLdb アプリケーションの一部を宣言ベースの sqlalchemy に適合させようとしています。私はsqlalchemyから始めたばかりです。

従来のテーブルは次のように定義されています。

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

それぞれに 3 つのテーブル ( student_tmpstudent_yearstudent_summerchoice_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 つのクラスになります)、クエリが必要になるたびに、フィルター処理を忘れないようにする必要がありますか?

ポインタをありがとう。

編集: データベースへの変更アクセス権がありません (ビューを作成できません)。両方のデータベースが同じサーバー上にない可能性があります (そのため、2 番目の DB にビューを作成できません)。

condition私の懸念は、およびでフィルタリングする前に、完全なテーブル スキャンを避けることchoice_idです。

EDIT 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): ...

さて、1 セットのテーブルに対して正しい 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')

そこから詳しく説明します...

ありがとう@バン

于 2012-05-26T06:16:07.487 に答える