sql >> データベース >  >> RDS >> Mysql

SQLAlchemyを使用して2つのデータベースのテーブルを結合する

    MySQLでは、データベースはスキーマと同義です 。たとえば、Postgresqlでデータベース内の複数のスキーマ間でクエリを実行できますが、データベース間で(直接)クエリを実行することはできませんが、MySQLでは2つのデータベースに区別がないため、複数のデータベース間でクエリを実行できます。

    この観点から、MySQLでのマルチデータベースクエリに対する可能な解決策は、単一のエンジン、セッション、およびBaseを使用して両方のスキーマを処理し、schema キーワード引数 テーブルに追加するか、両方のスキーマを反映して完全に修飾します。

    私はあなたのデータを持っていないので、sopythonとsopython2というテストサーバー上に2つのスキーマ(MySQLデータベース)を作成しました:

    mysql> create database sopython;
    Query OK, 1 row affected (0,00 sec)
    
    mysql> create database sopython2;
    Query OK, 1 row affected (0,00 sec)
    

    それぞれにテーブルを追加しました:

    mysql> use sopython
    Database changed
    mysql> create table foo (foo_id integer not null auto_increment primary key, name text);
    Query OK, 0 rows affected (0,05 sec)
    
    mysql> insert into foo (name) values ('heh');
    Query OK, 1 row affected (0,01 sec)
    
    mysql> use sopython2
    Database changed
    mysql> create table bar (bar_id integer not null auto_increment primary key, foo_id integer, foreign key (foo_id) references `sopython`.`foo` (foo_id)) engine=InnoDB;
    Query OK, 0 rows affected (0,07 sec)
    
    mysql> insert into bar (foo_id) values (1);
    Query OK, 1 row affected (0,01 sec)
    

    Pythonの場合:

    In [1]: from sqlalchemy import create_engine
    
    In [2]: from sqlalchemy.orm import sessionmaker
    
    In [3]: from sqlalchemy.ext.automap import automap_base
    
    In [4]: Session = sessionmaker()
    
    In [5]: Base = automap_base()
    

    デフォルトで使用するスキーマ(データベース)を指定せずにエンジンを作成します:

    In [6]: engine = create_engine('mysql+pymysql://user:[email protected]:6603/')
    
    In [7]: Base.prepare(engine, reflect=True, schema='sopython')
    
    In [8]: Base.prepare(engine, reflect=True, schema='sopython2')
    /home/user/SO/lib/python3.5/site-packages/sqlalchemy/ext/declarative/clsregistry.py:120: SAWarning: This declarative base already contains a class with the same class name and module name as sqlalchemy.ext.automap.foo, and will be replaced in the string-lookup table.
      item.__name__
    

    警告は私が完全には理解していないものであり、おそらく2つのテーブル間の外部キー参照がfooの再反映を引き起こした結果ですが、問題は発生していないようです。

    警告は、prepare()への2回目の呼び出しの結果です。 最初の呼び出しに反映されたテーブルのクラスを再作成して置き換えます。それをすべて回避する方法は、最初にメタデータを使用して両方のスキーマのテーブルを反映し、次に準備することです。

    Base.metadata.reflect(engine, schema='sopython')
    Base.metadata.reflect(engine, schema='sopython2')
    Base.prepare()
    

    この後、fooとbarの結合をクエリできます:

    In [9]: Base.metadata.bind = engine
    
    In [10]: session = Session()
    
    In [11]: query = session.query(Base.classes.bar).\
        ...:     join(Base.classes.foo).\
        ...:     filter(Base.classes.foo.name == 'heh')
    
    In [12]: print(query)
    SELECT sopython2.bar.bar_id AS sopython2_bar_bar_id, sopython2.bar.foo_id AS sopython2_bar_foo_id 
    FROM sopython2.bar INNER JOIN sopython.foo ON sopython.foo.foo_id = sopython2.bar.foo_id 
    WHERE sopython.foo.name = %(name_1)s
    
    In [13]: query.all()
    Out[13]: [<sqlalchemy.ext.automap.bar at 0x7ff1ed7eee10>]
    
    In [14]: _[0]
    Out[14]: <sqlalchemy.ext.automap.bar at 0x7ff1ed7eee10>
    
    In [15]: _.foo
    Out[15]: <sqlalchemy.ext.automap.foo at 0x7ff1ed7f09b0>
    



    1. OracleDatabaseからMariaDBへの移行-知っておくべきこと

    2. SQL-特定の値を持つ行をカウントする

    3. スキーマの移行:スターとの関係

    4. Android用SQLCipherを使い始める方法は?