Psycopg2/PostgreSQL 11.9:执行字符串->日期类型转换时“::”处或附近的语法错误

Psycopg2/PostgreSQL 11.9: Syntax error at or near "::" when performing string->date type cast

我正在使用 psycopg2 创建一个 table 分区并将一些行插入到这个新创建的分区中。 table 在日期类型列上进行 RANGE 分区。

Psycopg2 代码:

conn = connect_db()
cursor = conn.cursor()
sysdate = datetime.now().date()
sysdate_str = sysdate.strftime('%Y%m%d')
schema_name = "schema_name"
table_name = "transaction_log"

# Add partition if not exists for current day
sql_add_partition = sql.SQL("""
    CREATE TABLE IF NOT EXISTS {table_partition}
    PARTITION of {table}
    FOR VALUES FROM (%(sysdate)s) TO (maxvalue);
""").format(table = sql.Identifier(schema_name, table_name), table_partition = sql.Identifier(schema_name, f'{table_name}_{sysdate_str}'))
print(cursor.mogrify(sql_add_partition, {'sysdate': dt.date(2015,6,30)}))
cursor.execute(sql_add_partition, {'sysdate': sysdate})

cursor.mogrify() 的格式化输出:

CREATE TABLE IF NOT EXISTS "schema_name"."transaction_log_20211001"
PARTITION of "schema_name"."transaction_log"
FOR VALUES FROM ('2021-10-01'::date) TO (maxvalue);

收到错误:

ERROR:  syntax error at or near "::"
LINE 3: for values FROM ('2021-10-01'::date) TO (maxvalue);

有趣的是,psycopg2 似乎试图使用“::date”语法将字符串“2021-10-01”转换为日期对象,并且根据 postgreSQL 文档,这似乎是有效的(尽管文档中没有给出明确的示例),但是同时使用 pyscopg2 和在 postgreSQL 查询编辑器中执行该语句会产生此语法错误。但是在postgreSQLSQL编辑器中执行如下语句成功:

CREATE TABLE IF NOT EXISTS "schema_name"."transaction_log_20211001"
PARTITION of "schema_name"."transaction_log"
FOR VALUES FROM ('2021-10-01') TO (maxvalue);

关于如何让 psycopg2 正确格式化查询有什么想法吗?

跟进@LaurenzAlbe 的评论:


sql_add_partition = sql.SQL("""
    CREATE TABLE IF NOT EXISTS {table_partition}
    PARTITION of {table}
    FOR VALUES FROM (%(sysdate)s) TO (maxvalue);
""").format(table = sql.Identifier(schema_name, table_name), table_partition = sql.Identifier(schema_name, f'{table_name}_{sysdate_str}'))
print(cursor.mogrify(sql_add_partition, {'sysdate': '2021-10-01'}))

#OR

sql_add_partition = sql.SQL("""
    CREATE TABLE IF NOT EXISTS {table_partition}
    PARTITION of {table}
    FOR VALUES FROM ({sysdate}) TO (maxvalue);
""").format(table = sql.Identifier(schema_name, table_name), 
table_partition = sql.Identifier(schema_name, f'{table_name}_{sysdate_str}'),
sysdate=sql.Literal('2021-10-01'))
print(cursor.mogrify(sql_add_partition))

#Formatted as

CREATE TABLE IF NOT EXISTS "schema_name"."transaction_log_20211001"
    PARTITION of "schema_name"."transaction_log"
    FOR VALUES FROM ('2021-10-01') TO (maxvalue);

将日期作为文字值而不是日期对象传递。 psycopg2 将日期(时间)对象自动适配为 Postgres date/timestamp 类型(Datetime adaptation),这就是困扰你的地方。

更新

根据我的评论,这里解释了它需要是文字的原因 Create Table:

Each of the values specified in the partition_bound_spec is a literal, NULL, MINVALUE, or MAXVALUE. Each literal value must be either a numeric constant that is coercible to the corresponding partition key column's type, or a string literal that is valid input for that type.