Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Verbinden Sie Tabellen in zwei Datenbanken mit SQLAlchemy

In MySQL sind Datenbanken gleichbedeutend mit Schemas . Während Sie beispielsweise in Postgresql zwischen mehreren Schemas in einer Datenbank abfragen können, aber nicht zwischen Datenbanken (direkt), können Sie in MySQL zwischen mehreren Datenbanken abfragen, da es keinen Unterschied zwischen den beiden gibt.

Vor diesem Hintergrund könnte eine mögliche Lösung für Ihre Multi-Datenbank-Abfrage in MySQL darin bestehen, eine einzelne Engine, Sitzung und Base zu verwenden, die sowohl Ihre Schemas handhabt als auch den schema Schlüsselwortargument zu Ihren Tabellen hinzufügen oder beide Schemas widerspiegeln, sodass sie vollständig qualifiziert sind.

Da ich Ihre Daten nicht habe, habe ich 2 Schemata (MySQL-Datenbanken) auf einem Testserver namens sopython und sopython2 erstellt:

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

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

und fügte in jedem eine Tabelle hinzu:

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)

In 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()

Erstellen Sie die Engine, ohne anzugeben, welches Schema (Datenbank) Sie standardmäßig verwenden:

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__

Die Warnung ist etwas, das ich nicht ganz verstehe, und ist wahrscheinlich ein Ergebnis der Fremdschlüsselreferenz zwischen den beiden Tabellen, die eine erneute Reflexion von foo verursacht, aber es scheint keine Probleme zu verursachen.

Die Warnung ist das Ergebnis des zweiten Aufrufs von prepare() Neuerstellen und Ersetzen der Klassen für die im ersten Aufruf wiedergegebenen Tabellen. Um all das zu vermeiden, spiegeln Sie zuerst die Tabellen aus beiden Schemas mithilfe der Metadaten wider und bereiten dann Folgendes vor:

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

Danach können Sie die Verbindung von foo und bar abfragen:

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>