2017-06-15 11 views
1

私は2つのMySQLデータベースを扱っています。 SQLAlchemyのDB2のテーブルを使って、DB 1のテーブルに参加したいと思います。SQLAlchemyを使用して2つのデータベースにテーブルを結合する

次のようにSQLAlchemyの中でデータアクセス層を作成しながら、私は

、私はこのような参加作っていますクラスは

class T1D1_Repo(): 


    def __init__(self, dbHandle): 
     # create a cursor 
     self.Table_ = dbHandle.Base_.classes.t1 
     self.session_ = dbHandle.session_ 

のようなものです...

class DBHandleBase(object): 

    def __init__(self, connection_string='mysql+pymysql://root:[email protected]/services', pool_recycle=3600): 
      self.Base_ = automap_base() 
      self.engine_ = create_engine(connection_string, 
             pool_recycle = pool_recycle) 
      self.Base_.prepare(self.engine_, reflect=True) 
      self.session_ = Session(self.engine_) 

そして、私のテーブルをautomap_baseを使用しています

db1_handle = DB1_Handle() 
db2_handle = DB2_Handle() 
t1d1_repo = T1D1_Repo(handle) 
t1d2_repo = T1D2_Repo(person_handle) 

result = t1d1_repo.session_.query(
      t1d1_repo.Table_, 
      t1d2_repo.Table_).join(t1d2_repo.Table_, (
       t1d1_repo.Table_.person_id 
       == t1d2_repo.Table_.uuid)) 

このようなエラーが発生しました:

sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) (1146, "Table 'db1.t1d2' doesn't exist") [SQL: 'SELECT 

データベースdb1にテーブルt1を作成し、データベースdb2にテーブルt2を作成しました。

sqlalchemy ORMの2つのデータベーステーブル間で結合は可能ですか? これを達成するには?

+0

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

すべてこの後、あなたはfooとbarに参加問い合わせることができますこれは不可能です(ish)。たとえば、db1に対してSQLクエリを実行することはできませんし、db2内のテーブルをクエリできることを期待することはできません。それらのテーブルを別々にクエリし、結果をPythonで「結合」する必要があります。さて、外部テーブルをサポートしているDBを使用する場合は、DBをリンクして、別のDBのテーブルを外部テーブルとして導入することができます。しかし、MySQLがそれをサポートしているかどうかは分かりません。 –

+0

関連:https://stackoverflow.com/questions/1565993/oracle-database-link-mysql-equivalentおよびhttps://stackoverflow.com/questions/9416871/qualifying-table-names-with-database-names-in -sqlalchemy。前のコメントの「不可能」は少し強固な声明だった。 MySQLは、同じサーバー上に存在する場合はデータベース間でクエリを実行し、次にFEDERATEDストレージエンジンがある場合はクエリを実行できます。 –

+0

データベースは同じサーバーにありますか? –

答えて

1

In databases are synonymous with schemas。たとえば、PostgreSQLではデータベース内の複数のスキーマを照会することはできますが、データベース間では照会することはできません(直接)。

このように、MySQLでの複数データベースクエリの可能な解決策は、両方のスキーマを処理してschema keyword argumentをテーブルに渡すか、両方のスキーマを反映するように、単一のエンジン、セッション、完全修飾された

私はあなたのデータを持っていないので、私は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() 

はあなたがDEFAによって使用されたスキーマ(データベース)を指定せずにエンジンを作成します。 ULT:

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__ 

警告は、私は完全には理解していないものです、そしておそらくFOOの再反射を引き起こして2つのテーブル間の外部キー参照の結果であるが、それは問題を引き起こすようには見えません。


警告は、最初の呼び出しに反映テーブルのクラスを再作成し、交換prepare()に2回目の呼び出しの結果です。すべてのことは、第1のメタデータを使用して両方のスキーマからテーブルを反映して、準備しているを回避する方法:

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> 
+0

ありがとう@Ilja Everilaは面白い解決策のようです。私は間違いなくそれを試してみます。 –

関連する問題