【问题标题】:How to force SQLAlchemy to convert Boolean type from PostgreSQL to Bit type from SQL Server如何强制 SQLAlchemy 将布尔类型从 PostgreSQL 转换为 SQL Server 中的位类型
【发布时间】:2021-10-11 10:43:54
【问题描述】:

我正在尝试将几个表从一个数据库(“db1”,PostgreSQL)复制到另一个(“db2”,SQL Server)。 不幸的是,由于 PostgreSQL 数据库中某些字段的 BOOLEAN 类型未被识别为 SQL Server 的有效类型,我遇到了一个问题。

这是我的代码示例:

db2_engine = "postgresql+psycopg2://" + str(db2_user) + ":" + str(db2_password) + "@" + str(db2_host) + ":" + str(db2_port) + "/" + str(db2_database)
db2 = sqlalchemy.create_engine(db2_engine)

lst_tablename_totr = ["contract",
                     "subscription",
                     "contractdelivery",
                     "businesspartner"
                     ]

for table_name in lst_tablename_totr:
    table = Table(table_name, metadata, autoload=True, autoload_with=db2)
    table.create(bind=db1)
    query = """
    SELECT
        *
    FROM """ + str(table_name) + """
    """
    df_hg = pd.read_sql(query, db2_engine)
    df_hg.to_sql(table_name, db1, schema='dbo', index=False, if_exists='append')

目前,问题位于代码的table = Table(table_name, metadata, autoload=True, autoload_with=db_hgzl) table.create(bind=db1) 部分。

这是错误信息:

ProgrammingError: (pyodbc.ProgrammingError) ('42000', '[42000] [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]列、参数或变量 #8\xa0: 找不到数据类型 BOOLEAN。 (2715) (SQLExecDirectW)')

我找不到任何方法来强制在 PostgreSQL 布尔类型和 SQL Server 位类型之间进行转换。

【问题讨论】:

  • 你说 db2 还是 MSQL 我有点困惑:db2_engine = "postgresql+psycopg2://"
  • 如果您使用 Postgres ODBC,则此 Config 有一个配置设置。如果您想直接使用psycopg2,您可以创建并注册一个type caster 以转换为int

标签: python sql-server postgresql sqlalchemy


【解决方案1】:

您会看到 SQLAlchemy 的特定方言 BOOLEAN 类型与其通用 Boolean 类型之间的差异。对于现有的 PostgreSQL 表

CREATE TABLE IF NOT EXISTS public.so68683260
(
    id character varying(5) COLLATE pg_catalog."default" NOT NULL,
    bool_col boolean NOT NULL,
    CONSTRAINT so68683260_pkey PRIMARY KEY (id)
)

如果我们反映该表,则布尔列定义为BOOLEAN

tbl = sa.Table(table_name, sa.MetaData(), autoload_with=pg_engine)
print(type(tbl.columns["bool_col"].type))
# <class 'sqlalchemy.sql.sqltypes.BOOLEAN'>

然后如果我们尝试在 SQL Server 中创建表,我们最终会做相当于

tbl = sa.Table(
    table_name,
    sa.MetaData(),
    sa.Column("id", sa.VARCHAR(5), primary_key=True),
    sa.Column("bool_col", sa.BOOLEAN, nullable=False),
)

tbl.drop(ms_engine, checkfirst=True)
tbl.create(ms_engine)

并且您引用的错误失败,因为呈现的 DDL 是

CREATE TABLE so68683260 (
    id VARCHAR(5) NOT NULL, 
    bool_col BOOLEAN NOT NULL, 
    PRIMARY KEY (id)
)

但是,如果我们使用通用的Boolean 类型

tbl = sa.Table(
    table_name,
    sa.MetaData(),
    sa.Column("id", sa.VARCHAR(5), primary_key=True),
    sa.Column("bool_col", sa.Boolean, nullable=False),
)

tbl.drop(ms_engine, checkfirst=True)
tbl.create(ms_engine)

我们成功了,因为渲染的 DDL 是

CREATE TABLE so68683260 (
    id VARCHAR(5) NOT NULL, 
    bool_col BIT NOT NULL, 
    PRIMARY KEY (id)
)

BIT 是 T-SQL 中有效的对应列类型。

如果您认为应该改变这种行为,请随时打开SQLAlchemy issue

[另请注意,文本列是VARCHAR(5),因为该表使用我的 PostgreSQL 测试数据库 (UTF8) 的默认编码,但在 SQL Server 中创建该表将创建一个 VARCHAR(非 Unicode)列NVARCHAR (Unicode) 列。]

【讨论】:

  • 我一直和你在一起,直到你走到最后和 varchar。 Postgres varchar(或其他字符串类型)并不总是 Unicode,请参阅此处Character Sets:“PostgreSQL 中的字符集支持允许您以各种字符集(也称为编码)存储文本,包括单字节字符集,例如作为 ISO 8859 系列和多字节字符集,例如 EUC(扩展 Unix 代码)、UTF-8 和 Mule 内部代码。”即使那是真的,我也不明白为什么会是VARCHAR 而不是NVARCHAR
  • @AdrianKlaver - 感谢您的更正。与 SQL Server 不同,PostgreSQL 没有单独的 VARCHAR/NVARCHAR 类型,并且列反映为 VARCHAR。当 SQL Server 看到 VARCHAR 时,它会创建一个非 Unicode 列。我怀疑反之亦然:SQL Server 表可能有一个列反映为 NVARCHAR,这可能会导致 PostgreSQL 抛出类似“类型“nvarchar”不存在”的错误。
猜你喜欢
  • 1970-01-01
  • 2012-03-12
  • 2015-12-17
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
  • 2014-02-04
  • 2021-03-02
相关资源
最近更新 更多