我正在尝试使用SQLAlchemy在不同的rdbms之间复制表模式 - 在本例中是从MSSQL到MySQL。
有没有办法获取表对象并将元数据复制并转换为不同的方言?
我尝试了tometadata()函数,但列的类型信息保留在原始的mssql方言中。
只要列类型兼容,它就可以正常工作,但在MySQL中不存在列类型时会中断,例如。 uniqueidentifier,varchar(max)等
import sqlalchemy as sa
# Source table details
source_table_name = 'Customer'
source_schema_name = 'AdventureWorksLT2008.SalesLT'
db_uri_mssql = "mssql+pyodbc://{user}:{password}@{dsn}"
db_uri_mysql = "mysql+mysqlconnector://{user}:{password}@{host}:{port}/{db}"
source_db = db_uri_mssql.format(user=source_user, password=source_password, dsn=source_dsn)
target_db = db_uri_mysql.format(user=target_user, password=target_password, \
host=target_host, db=target_db, port=target_port)
source_engine = sa.create_engine(source_db, echo=False, convert_unicode=True, legacy_schema_aliasing=False)
target_engine = sa.create_engine(target_db, echo=False, convert_unicode=True)
source_meta = sa.MetaData(bind=source_engine)
target_meta = sa.MetaData(bind=target_engine)
source_table = sa.Table(source_table_name, source_meta, autoload=True, schema=source_schema_name)
target_table = source_table.tometadata(target_meta, schema=None)
target_table.create(target_engine, checkfirst=True)
这是我得到的错误:
Traceback (most recent call last):
File "/Users/josh/PycharmProjects/Dmigrate3/Dmigrate3.py", line 38, in
target_table.create(target_engine, checkfirst=True)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/schema.py", line 725, in create
checkfirst=checkfirst)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1854, in _run_visitor
conn._run_visitor(visitorcallable, element, **kwargs)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1481, in _run_visitor
**kwargs).traverse_single(element)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 121, in traverse_single
return meth(obj, **kw)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 764, in visit_table
include_foreign_key_constraints=include_foreign_key_constraints
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 914, in execute
return meth(self, multiparams, params)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 68, in _execute_on_connection
return connection._execute_ddl(self, multiparams, params)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 962, in _execute_ddl
compiled = ddl.compile(dialect=dialect)
File "", line 1, in
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 494, in compile
return self._compiler(dialect, bind=bind, **kw)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/ddl.py", line 26, in _compiler
return dialect.ddl_compiler(dialect, self, **kw)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 190, in __init__
self.string = self.process(self.statement, **compile_kwargs)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 213, in process
return obj._compiler_dispatch(self, **kwargs)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
return meth(self, **kw)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 2167, in visit_create_table
(table.description, column.name, ce.args[0])
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 2156, in visit_create_table
and not first_pk)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 213, in process
return obj._compiler_dispatch(self, **kwargs)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 81, in _compiler_dispatch
return meth(self, **kw)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 2187, in visit_create_column
first_pk=first_pk
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/dialects/mysql/base.py", line 1954, in get_column_specification
column.type, type_expression=column)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/compiler.py", line 261, in process
return type_._compiler_dispatch(self, **kw)
File "/Users/josh/Dmig3/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 79, in _compiler_dispatch
raise exc.UnsupportedCompilationError(visitor, cls)
sqlalchemy.exc.CompileError: (in table 'Customer', column 'rowguid'): Compiler can't render element of type
答案 0 :(得分:2)
实际上,您需要在目标RDBMS中为每个无法自动映射的类型定义等效类型。
实现这一目标的一种方法是定义自己的编译扩展名:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.dialects.mssql import UNIQUEIDENTIFIER, VARCHAR
@compiles(UNIQUEIDENTIFIER, 'mysql')
def compile_UNIQUEIDENTIFIER_mssql_mysql(element, compiler, **kw):
""" Handles mssql UNIQUEIDENTIFIER datatype as VARCHAR in MySQL """
try:
length = element.length
except:
length = None
element.length = 64 # @note: 36 should be enough, but see the link below
# @note: since SA-0.9 all string types have collation, which are not
# really compatible between databases, so use default one
element.collation = None
res = compiler.visit_VARCHAR(element, **kw)
if length:
element.length = length
return res
@compiles(BIT, 'mysql')
def compile_BIT_mssql_mysql(element, compiler, **kw):
""" Handles mssql BIT datatype as BOOLEAN in mysql """
return compiler.visit_BOOLEAN(element, **kw)
然后运行你的代码,希望它能正常工作。
注意:我不太了解MySQL,也不确定数据类型的最佳映射,但我看了10.5.4 Microsoft SQL Server Type Mapping的信息。