sql 可以运行,但是当你用 sqlalchemy 运行 python 代码时你失败了

Posted

技术标签:

【中文标题】sql 可以运行,但是当你用 sqlalchemy 运行 python 代码时你失败了【英文标题】:sql is ok to run but when you run python code with sqlalchemy you failed 【发布时间】:2020-12-14 22:11:59 【问题描述】:

系统信息

mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 8.0.20    |
+-----------+
python -V
Python 2.7.12

sql运行正常

我用下面sqlalchemy输出的sql,建表就可以了。

CREATE TABLE images (
    created_at DATETIME,
    updated_at DATETIME,
    deleted_at DATETIME,
    deleted INTEGER,
    platform_id VARCHAR(36) NOT NULL,
    image_id VARCHAR(36) NOT NULL,
    PRIMARY KEY (platform_id, image_id)
);


CREATE TABLE flavors (
    created_at DATETIME,
    updated_at DATETIME,
    deleted_at DATETIME,
    deleted INTEGER,
    platform_id VARCHAR(36) NOT NULL,
    flavor_id VARCHAR(36) NOT NULL,
    PRIMARY KEY (platform_id, flavor_id)
);


CREATE TABLE security_groups (
    created_at DATETIME,
    updated_at DATETIME,
    deleted_at DATETIME,
    deleted INTEGER,
    platform_id VARCHAR(36) NOT NULL,
    name VARCHAR(255) NOT NULL,
    tenant_id VARCHAR(36),
    user_id VARCHAR(36),
    PRIMARY KEY (platform_id, name)
);


CREATE TABLE instances (
    created_at DATETIME,
    updated_at DATETIME,
    deleted_at DATETIME,
    deleted INTEGER,
    flavor_id VARCHAR(36),
    image_id VARCHAR(36),
    security_group_name VARCHAR(255),
    platform_id VARCHAR(36) NOT NULL,
    uuid VARCHAR(36) NOT NULL,
    user_id VARCHAR(36),
    tenant_id VARCHAR(36),
    `accessIPv4` VARCHAR(255),
    `accessIPv6` VARCHAR(255),
    progress INTEGER,
    config_drive BOOL,
    status VARCHAR(255),
    `hostId` VARCHAR(255),
    key_name VARCHAR(255),
    name VARCHAR(255),
    updated DATETIME,
    created DATETIME,
    launched_at DATETIME,
    terminated_at DATETIME,
    task_state VARCHAR(255),
    vm_state VARCHAR(255),
    instance_name VARCHAR(255),
    `diskConfig` VARCHAR(255),
    power_state INTEGER,
    availability_zone VARCHAR(255),
    host VARCHAR(255),
    hypervisor_hostname VARCHAR(255),
    PRIMARY KEY (platform_id, uuid),
    CHECK (config_drive IN (0, 1))
);

ALTER TABLE instances ADD CONSTRAINT flavor_instances_fk FOREIGN KEY(platform_id, flavor_id) REFERENCES flavors (platform_id, flavor_id)

但是当我使用我的迁移脚本时,它会失败并显示以下错误消息

发生错误:

Traceback(最近一次调用最后一次): _execute_context 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/base.py”,第 1277 行 游标、语句、参数、上下文 do_execute 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/default.py”,第 593 行 cursor.execute(语句,参数) 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/cursors.py”,第 163 行,在执行 结果 = self._query(查询) _query 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/cursors.py”,第 321 行 conn.query(q) 查询中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 505 行 self._affected_rows = self._read_query_result(无缓冲=无缓冲) _read_query_result 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 724 行 结果.read() 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 1069 行,读取 first_packet = self.connection._read_packet() _read_packet 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 676 行 packet.raise_for_error() 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/protocol.py”,第 223 行,在 raise_for_error err.raise_mysql_exception(self._data) raise_mysql_exception 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/err.py”,第 107 行 引发错误类(errno,errval) pymysql.err.OperationalError: (3780, "外键约束 'flavor_instances_fk' 中的引用列 'platform_id' 和引用列 'platform_id' 不兼容。")

上述异常是以下异常的直接原因:

Traceback(最近一次调用最后一次): 文件“/root/work/cpmsv2/cpmsv2/tests/functional/db/test_migrate.py”,第 118 行,在 name='flavor_instances_fk').create() 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/migrate/changeset/constraint.py”,第 44 行,在创建 self.__do_imports('constraintgenerator', *a, **kw) 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/migrate/changeset/constraint.py”,第 32 行,在 __do_imports run_single_visitor(引擎,visitorcallable,自我,*a,**kw) run_single_visitor 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/migrate/changeset/databases/visitor.py”,第 85 行 fn(元素,**kwargs) 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/migrate/changeset/ansisql.py”,第 285 行,在 visit_migrate_foreign_key_constraint self._visit_constraint(*p, **k) _visit_constraint 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/migrate/changeset/ansisql.py”,第 297 行 self.execute() 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/migrate/changeset/ansisql.py”,第 44 行,在执行 返回 self.connection.execute(self.buffer.getvalue()) 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/base.py”,第 1003 行,在执行 return self.execute_text(object, multiparams, params) _execute_text 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/base.py”,第 1178 行 参数, execute_context 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/base.py”,第 1317 行 e、语句、参数、游标、上下文 handle_dbapi_exception 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/base.py”,第 1511 行 sqlalchemy_exception,with_traceback=exc_info[2],来自=e 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/util/compat.py”,第 182 行,在 raise 引发异常 _execute_context 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/base.py”,第 1277 行 游标、语句、参数、上下文 do_execute 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/sqlalchemy/engine/default.py”,第 593 行 cursor.execute(语句,参数) 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/cursors.py”,第 163 行,在执行 结果 = self._query(查询) _query 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/cursors.py”,第 321 行 conn.query(q) 查询中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 505 行 self._affected_rows = self._read_query_result(无缓冲=无缓冲) _read_query_result 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 724 行 结果.read() 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 1069 行,读取 first_packet = self.connection._read_packet() _read_packet 中的文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/connections.py”,第 676 行 packet.raise_for_error() 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/protocol.py”,第 223 行,在 raise_for_error err.raise_mysql_exception(self._data) 文件“/root/.virtualenvs/cpmsv2/lib/python3.7/site-packages/pymysql/err.py”,第 107 行,在 raise_mysql_exception 引发错误类(errno,errval) sqlalchemy.exc.OperationalError:(pymysql.err.OperationalError)(3780,“外键约束'flavor_instances_fk'中的引用列'platform_id'和引用列'platform_id'不兼容。”) [SQL: ALTER TABLE 实例添加约束 flavor_instances_fk FOREIGN KEY(platform_id, flavor_id) REFERENCES flavor (platform_id, flavor_id)] (此错误的背景:http://sqlalche.me/e/13/e3q8) 详细表在上面的命名实例中被引用。 (此错误的背景:http://sqlalche.me/e/13/e3q8)

可以重现错误的最小代码段如下所示

from sqlalchemy import create_engine
from sqlalchemy import Boolean, Column, DateTime, Enum, Float
from sqlalchemy import dialects
from sqlalchemy import ForeignKey, ForeignKeyConstraint, Index, Integer, MetaData, PrimaryKeyConstraint, String, Table # noqa
from sqlalchemy import Text

connection_string = 'your_connect_string'
engine = create_engine(connection_string, echo=True)
meta = MetaData()
meta.bind = engine
tables = []


instances = Table(
    'instances', meta,
    # Created by TimestampMixin
    Column('created_at', DateTime),
    Column('updated_at', DateTime),
    # Created by SoftDeleteMixin
    Column('deleted_at', DateTime),
    Column('deleted', Integer),

    Column('flavor_id', String(36)),
    Column('image_id', String(36)),
    Column('security_group_name', String(255)),

    Column('platform_id', String(36), primary_key=True),
    Column('uuid', String(36), primary_key=True),
    Column('user_id', String(36)),
    Column('tenant_id', String(36)),


    Column('accessIPv4', String(255)),
    Column('accessIPv6', String(255)),
    Column('progress', Integer),
    Column('config_drive', Boolean),
    Column('status', String(255)),
    Column('hostId', String(255)),
    Column('key_name', String(255)),
    Column('name', String(255)),

    Column('updated', DateTime),
    Column('created', DateTime),
    Column('launched_at', DateTime),
    Column('terminated_at', DateTime),

    Column('task_state', String(255)),
    Column('vm_state', String(255)),
    Column('instance_name', String(255)),
    Column('diskConfig', String(255)),
    Column('power_state', Integer),
    Column('availability_zone', String(255)),
    Column('host', String(255)),
    Column('hypervisor_hostname', String(255)),
    mysql_engine='InnoDB',
    mysql_charset='utf8'
)


images = Table(
    'images', meta,
    # Created by TimestampMixin
    Column('created_at', DateTime),
    Column('updated_at', DateTime),
    # Created by SoftDeleteMixin
    Column('deleted_at', DateTime),
    Column('deleted', Integer),

    Column('platform_id', String(36), primary_key=True),
    Column('image_id', String(36), primary_key=True),
)


flavors = Table(
    'flavors', meta,
    # Created by TimestampMixin
    Column('created_at', DateTime),
    Column('updated_at', DateTime),
    # Created by SoftDeleteMixin
    Column('deleted_at', DateTime),
    Column('deleted', Integer),

    Column('platform_id', String(36), primary_key=True),
    Column('flavor_id', String(36), primary_key=True),
)


security_groups = Table(
    'security_groups', meta,
    # Created by TimestampMixin
    Column('created_at', DateTime),
    Column('updated_at', DateTime),
    # Created by SoftDeleteMixin
    Column('deleted_at', DateTime),
    Column('deleted', Integer),

    Column('platform_id', String(36), primary_key=True),
    Column('name', String(255), primary_key=True),

    Column('tenant_id', String(36)),
    Column('user_id', String(36)),
)


tables.append(images)
tables.append(flavors)
tables.append(security_groups)
tables.append(instances)

meta.create_all(tables=tables)
from migrate import ForeignKeyConstraint, UniqueConstraint

# UniqueConstraint(instances.c.platform_id, instances.c.flavor_id,
#                  name='platform_flavor_constraint').create()
ForeignKeyConstraint([instances.c.platform_id, instances.c.flavor_id],
                     [flavors.c.platform_id, flavors.c.flavor_id],
                     name='flavor_instances_fk').create()
ForeignKeyConstraint([instances.c.platform_id, instances.c.image_id],
                     [images.c.platform_id, images.c.image_id],
                     name='image_instances_fk').create()
ForeignKeyConstraint([instances.c.platform_id, instances.c.security_group_name], # noqa
                     [security_groups.c.platform_id, security_groups.c.name],
                     name='sec_groups_instances_fk').create() # noqa

【问题讨论】:

【参考方案1】:

朋友yiwei提醒,instancesflavors这两个表的数据库的charset和collect是不同的。

参考代码如下

    Column('hypervisor_hostname', String(255)),
    mysql_engine='InnoDB',
    mysql_charset='utf8'

其他表没有以下代码sn-p

    mysql_engine='InnoDB',
    mysql_charset='utf8'

【讨论】:

以上是关于sql 可以运行,但是当你用 sqlalchemy 运行 python 代码时你失败了的主要内容,如果未能解决你的问题,请参考以下文章

从 SQLAlchemy 中的文件执行 SQL

sqlalchemy : 使用参数绑定执行原始 sql

当你无法登录SourceTree?

使用 sqlalchemy 会话执行 sql 会大大减慢执行时间

Oracle 表未拥有的 SqlAlchemy 反映

无法使用 sqlalchemy 建立连接 SQL Server