使用SQLAlchemy

时间:2015-06-20 02:55:41

标签: sqlalchemy

我正在尝试使用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 


1 个答案:

答案 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的信息。