使用 SQLAlchemy 连接两个数据库中的表
Join tables in two databases using SQLAlchemy
我正在使用两个 MySQL 数据库。我想在 SQLAlchemy 中加入来自 DB 1 的 table 和来自 DB2 的 table。
我正在使用 automap_base 在 sqlalchemy 中创建数据访问层,如下所示...
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_)
我的 table 的 Class 就像
class T1D1_Repo():
def __init__(self, dbHandle):
# create a cursor
self.Table_ = dbHandle.Base_.classes.t1
self.session_ = dbHandle.session_
我是这样连接的,
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 中创建了 table t1,在数据库 db2 中创建了 table t2。
在 sqlalchemy ORM 中是否可以跨两个数据库进行连接 table?
如何实现?
在MySQLdatabases are synonymous with schemas。例如,在 Postgresql 中,您可以在数据库中的多个模式之间查询,但不能(直接)在数据库之间查询,您可以在 MySQL 中的多个数据库之间查询,因为两者之间没有区别。
鉴于此,您在 MySQL 中的多数据库查询的可能解决方案可能是使用单个引擎、会话和 Base 来处理您的模式并将 schema
keyword argument 传递给您的 tables,或反映两种模式,使它们完全合格。
因为我没有你的数据,所以我在名为 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)
并在每个中添加了一个table:
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__
这个warning是我不太明白的地方,估计是2个table之间的外键引用导致foo的重新反射,不过貌似没有出问题.
警告是第二次调用 prepare()
为第一次调用中反映的 table 重新创建和替换 类 的结果。避免所有这些的方法是首先使用元数据反映来自两个模式的 tables,然后准备:
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>
我正在使用两个 MySQL 数据库。我想在 SQLAlchemy 中加入来自 DB 1 的 table 和来自 DB2 的 table。
我正在使用 automap_base 在 sqlalchemy 中创建数据访问层,如下所示...
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_)
我的 table 的 Class 就像
class T1D1_Repo():
def __init__(self, dbHandle):
# create a cursor
self.Table_ = dbHandle.Base_.classes.t1
self.session_ = dbHandle.session_
我是这样连接的,
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 中创建了 table t1,在数据库 db2 中创建了 table t2。
在 sqlalchemy ORM 中是否可以跨两个数据库进行连接 table? 如何实现?
在MySQLdatabases are synonymous with schemas。例如,在 Postgresql 中,您可以在数据库中的多个模式之间查询,但不能(直接)在数据库之间查询,您可以在 MySQL 中的多个数据库之间查询,因为两者之间没有区别。
鉴于此,您在 MySQL 中的多数据库查询的可能解决方案可能是使用单个引擎、会话和 Base 来处理您的模式并将 schema
keyword argument 传递给您的 tables,或反映两种模式,使它们完全合格。
因为我没有你的数据,所以我在名为 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)
并在每个中添加了一个table:
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__
这个warning是我不太明白的地方,估计是2个table之间的外键引用导致foo的重新反射,不过貌似没有出问题.
警告是第二次调用 prepare()
为第一次调用中反映的 table 重新创建和替换 类 的结果。避免所有这些的方法是首先使用元数据反映来自两个模式的 tables,然后准备:
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>