I am working with two MySQL Databases. I want to join a table from DB 1 with a table from DB2 in SQLAlchemy.
I am using automap_base while creating data access layer in sqlalchemy as follows...
class DBHandleBase(object):
def __init__(self, connection_string='mysql+pymysql://root:xxxxxxx@localhost/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_)
And my tables Class is like
class T1D1_Repo():
def __init__(self, dbHandle):
# create a cursor
self.Table_ = dbHandle.Base_.classes.t1
self.session_ = dbHandle.session_
I am making the join like this,
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))
I am getting the error like this:
sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) (1146, "Table 'db1.t1d2' doesn't exist") [SQL: 'SELECT
we have created table t1 in database db1 and table t2 in database db2.
Do join is possible across two databases table in sqlalchemy ORM? How to achieve that?
答案 0 :(得分:7)
在MySQL databases are synonymous with schemas中。例如,在Postgresql中,您可以在数据库中的多个模式之间进行查询,但不能在数据库之间进行查询(直接),您可以在MySQL中的多个数据库之间进行查询,因为两者之间没有区别。
从这个角度来看,MySQL中多数据库查询的一个可能的解决方案可能是使用单个引擎,会话和Base来处理你的模式并将schema
keyword argument传递给你的表,或反映两个模式所以他们完全合格。
由于我没有你的数据,我在名为sopython和sopython2的测试服务器上制作了两个模式(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:pass@: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重新反映的结果,但它似乎没有造成麻烦。
警告是第二次调用prepare()
重新创建并替换第一次调用中反映的表的类的结果。避免所有这些的方法是首先使用元数据反映两个模式中的表,然后准备:
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>