SQLAlchemy: отражающие таблицы существующей базы данных не работают должным образом - PullRequest
0 голосов
/ 21 апреля 2020

В настоящее время я занимаюсь оценкой SQLAlchemy для нового проекта. При попытке отразить таблицы существующей базы данных (postgres, oracle) у меня возникают некоторые проблемы.

Для подключения к базе данных Oracle используется следующий код:

from sqlalchemy import create_engine, MetaData, Table, inspect, select
import pandas as pd
import keyring

dbtype = 'Oracle'
dbenv = 'LOCAL'
dbname = 'MYDB'
dbsys = '%s%s' % (dbtype, dbenv)
dbusr = 'myusr'
dbpwd = keyring.get_password(dbsys, dbusr)
dbhost = 'mydbhost'
dbport = 1521

dbconstr = 'oracle+cx_oracle://%s:%s@%s:%s/%s' % (dbusr, dbpwd, dbhost, dbport, dbname)
engine = create_engine(dbconstr)

После некоторых проб и ошибок относительно того, как собрать строку подключения (в моей системе нет tnsnames.ora), мне удалось успешно установить sh соединение с удаленным Oracle database.

При проверке базы данных и попытке извлечь имена доступных таблиц я получил пустой список.

inspector = inspect(engine)
instbls = inspector.get_table_names()
print('instbls: %s' % instbls)

# instbls: []

На самом деле я ожидал, что системные таблицы или таблицы publi c были бы перечислены.

Далее я попытался отразить таблицы базы данных схемы SYS.

md01 = MetaData(bind=engine, schema=['SYS', 'SYSTEM'], reflect=True)
# Warning: sqlalchemy_oracle.py:37: SADeprecationWarning: The MetaData.reflect flag is deprecated and will be removed in a future release.   Please use the MetaData.reflect() method.

print('type(md01): %s' % type(md01))
# type(md01): <class 'sqlalchemy.sql.schema.MetaData'>

md01tbls = md01.tables
print('md01tbls: %s' % md01tbls)
# md01tbls: immutabledict({})

Поэтому я изменил код соответствующим образом, чтобы получить избавиться от предупреждения

md02 = MetaData(bind=engine, schema=['SYS', 'SYSTEM']).reflect()
print('type(md02): %s' % type(md02))
# type(md02): <class 'NoneType'>

md02tbls = md02.tables
# Exception: Traceback (most recent call last):
#    ...
# File "sqlalchemy_oracle.py", line 44, in <module>
# AttributeError: 'NoneType' object has no attribute 'tables'

print('md02tbls: %s' % md02tbls)

Нет предупреждения, но есть исключение. : (

После некоторых исследований Net выглядело так, как будто требуется дальнейшая модификация кода.

md03 = MetaData().reflect(bind=engine, schema=['SYS', 'SYSTEM'])
# Exception: Traceback (most recent call last):
#    ...
# File "/site-packages/sqlalchemy/engine/default.py", line 637, in denormalize_name
#    name_lower = name.lower()
# AttributeError: 'list' object has no attribute 'lower'

print('type(md03): %s' % type(md03))
md03tbls = md03.tables
print('md03tbls: %s' % md03tbls)

Даже менее успешный, чем предыдущая попытка. Преобразование имен схем, перечисленных ниже буквы в регистре приводят к одинаковому результату.

Так что, может быть, reflect может обрабатывать только strings, а не lists?

md05a = MetaData().reflect(bind=engine, schema='sys')
print('type(md05a): %s' % type(md05a))
# type(md05a): <class 'NoneType'>

md05b = MetaData().reflect(bind=engine, schema='system')
print('type(md05b): %s' % type(md05b))
# type(md05b): <class 'NoneType'>

md05atbls = md05a.tables
# Exception: Traceback (most recent call last):
#    ...
# File "sqlalchemy_oracle.py", line 44, in <module>
# AttributeError: 'NoneType' object has no attribute 'tables'

print('md05atbls: %s' % md05atbls)
md05btbls = md05b.tables
print('md05btbls: %s' % md05btbls)

Там тоже не повезло!

Может быть, невозможно отобразить системные таблицы? Итак, давайте попробуем указать пользовательские c объекты.

md06 = MetaData().reflect(bind=engine, schema='MYUSR')
print('type(md06): %s' % type(md06))
# type(md06): <class 'NoneType'>

md06tbls = md06.tables
# Exception: Traceback (most recent call last):
#    ...
# File "sqlalchemy_oracle.py", line 44, in <module>
# AttributeError: 'NoneType' object has no attribute 'tables'

print('md06tbls: %s' % md06tbls)

Снова уже известное исключение.

Возвращение к устаревшему вызову версия.

md07 = MetaData(bind=engine, schema=['MYUSR', 'MYUSR2'], reflect=True)
print('type(md07): %s' % type(md07))
# type(md07): <class 'sqlalchemy.sql.schema.MetaData'>

md07tbls = md07.tables
print('md07tbls: %s' % md07tbls)
# md07tbls: immutabledict({})

Не исключение, но и таблиц тоже нет, несмотря на то, что в схемах MYUSR и MYUSR2.

. *1046*

есть несколько разделений list на strings при указании схемы.

md08a = MetaData(bind=engine, schema='MYUSR', reflect=True)
# Warning: sqlalchemy_oracle.py:37: SADeprecationWarning: The MetaData.reflect flag is deprecated and will be removed in a future release.   Please use the MetaData.reflect() method.

print('type(md08a): %s' % type(md08a))
# ype(md08a): <class 'sqlalchemy.sql.schema.MetaData'>

md08b = MetaData(bind=engine, schema='MYUSR2', reflect=True)
# Warning: sqlalchemy_oracle.py:40: SADeprecationWarning: The MetaData.reflect flag is deprecated and will be removed in a future release.   Please use the MetaData.reflect() method.

print('type(md08b): %s' % type(md08b))
# type(md08b): <class 'sqlalchemy.sql.schema.MetaData'>

md08atbls = md08a.tables
print('md08atbls: %s' % md08atbls)
# md08atbls: immutabledict({'MYUSR.table01': Table(...)})

md08btbls = md08b.tables
print('md08btbls: %s' % md08btbls)
# md08btbls: immutabledict({'MYUSR2.table01': Table(...)})

Таким образом, эта попытка, наконец, дала ожидаемый результат.:)

Из всего этого все выглядит так, как будто

  1. системные / публичные c таблицы (объекты базы данных) не могут быть отражены;
  2. могут отображаться только пользовательские таблицы c;
  3. работает только устаревшая версия отражения;
  4. такое поведение можно наблюдать как с Oracle, так и с PostgreSQL баз данных.

Есть что-то, что я упустил? Что-то я неправильно понял? Сделано неправильно, в отличие от того, как оно на самом деле задумано?

Моя среда состоит из

  • Ubuntu linux 16.04LTS;
  • Python 3.8;
  • SQLAlchemy 1.3.16;
  • cx_ Oracle 7.3.0;
  • psycopg2 2.8.5;
  • локальный Oracle 18 c Мгновенный клиент ;
  • удаленная Oracle 19 c база данных;
  • локальная PostgreSQL 9,5 база данных.
...