You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在SQLAlchemy中处理大小写敏感列的MERGE更新问题

大小写敏感列在PostgreSQL模拟Snowflake环境下的查询与MERGE问题解决

问题背景

我正在为SQL代码编写测试,定义了如下ORM表:

class CompanyAddressORM(Base):
    __tablename__ = "company_address"

    pk = Column("pk", Text, primary_key=True)
    project_id = Column("PROJECT_ID", Integer)
    company_id = Column("COMPANY_ID", Integer)


class CompanyDocumentsORM(Base):
    __tablename__ = "company_documents"

    pk = Column("pk", Text, primary_key=True)
    project_id = Column("PROJECT_ID", Integer)
    company_id = Column("COMPANY_ID", Integer)
    page_id = Column("PAGE_ID", Integer)

底层代码使用Snowflake,无法修改原有代码,需通过testing.postgresql包模拟Snowflake连接执行查询,遇到了大小写敏感列的问题:

  • 直接查询大写列名报错:
session.execute("select PROJECT_ID from company_address")
>>> *** sqlalchemy.exc.ProgrammingError: (psycopg2.errors.UndefinedColumn) column "project_id" does not exist
  • 给列名加双引号后查询正常:
session.execute('select "PROJECT_ID" from company_address').all()
>>> [(1,), (2,), (3,), (4,), (5,)]

后续执行MERGE更新时问题更突出:原有MERGE在Snowflake中正常运行,但在SQLAlchemy中因大小写不敏感报错。尝试给所有列加双引号:

source_column_names = ", ".join(f'''"source.{col}"''' for col in columns)
target_column_updates = ", ".join(f'''"target.{col}" = "source.{col}"''' for col in columns)

# Generate the join condition for the merge query
join_condition = " AND ".join(
    f'''"target.{col}" = "source.{col}"''' for col in join_columns
)

生成的查询语句如下:

MERGE INTO company_address as target
    USING company_address_tmp as source
    ON "target.project_id" = "source.project_id"
    WHEN MATCHED THEN UPDATE SET
        .....

但执行该查询时出现编译错误;若去掉双引号,又会出现列不存在的错误。

解决方法

1. 修正双引号的使用方式

你当前的错误是把表别名+列名整体用双引号包裹了,PostgreSQL会把"target.project_id"当成一个完整的列名,而不是target表下的project_id列。正确的做法是只给列名加双引号,表别名不需要:

# 正确的列名拼接方式
source_column_names = ", ".join(f'source."{col}"' for col in columns)
target_column_updates = ", ".join(f'target."{col}" = source."{col}"' for col in columns)

join_condition = " AND ".join(
    f'target."{col}" = source."{col}"' for col in join_columns
)

生成的MERGE语句会变成:

MERGE INTO company_address as target
    USING company_address_tmp as source
    ON target."PROJECT_ID" = source."PROJECT_ID"
    WHEN MATCHED THEN UPDATE SET
        target."COMPANY_ID" = source."COMPANY_ID"
        .....

2. 让SQLAlchemy自动处理大小写敏感列

如果不想手动拼接双引号,可以通过SQLAlchemy的配置让它自动为列名添加双引号:

在创建引擎时,开启quote_all_identifiers参数:

from sqlalchemy import create_engine

# 针对testing.postgresql的引擎配置
engine = create_engine(
    postgresql_url,
    connect_args={"options": "-c quote_all_identifiers=on"}
)

开启后,SQLAlchemy会自动给所有标识符(表名、列名)添加双引号,避免大小写转换问题。

3. 模拟Snowflake的大小写行为

Snowflake默认保留标识符的大小写(用双引号包裹时),而PostgreSQL默认会把未加双引号的标识符转为小写。可以在测试环境初始化PostgreSQL时,修改数据库参数让它和Snowflake行为对齐:

from testing.postgresql import Postgresql

with Postgresql(
    initdb_args=["--lc-collate=C", "--lc-ctype=C"],
    postgres_args=["-c", "sql_identifier_case=upper"]
) as pg:
    # 在这里创建连接、执行测试
    pass

这样PostgreSQL会把未加双引号的标识符视为大写,和Snowflake的行为一致,无需手动添加双引号。

内容的提问来源于stack exchange,提问作者Drivebyluna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:23:10