#python #sql #postgresql #psycopg2
Вопрос:
Я использую psycopg2 для создания раздела таблицы и вставки некоторых строк в этот недавно созданный раздел. Таблица разделена на диапазоны по столбцу типа даты.
Код 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})
Форматированный вывод курсора.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, похоже, пытается привести строку ‘2021-10-01’ к объекту даты с синтаксисом «::дата», и, согласно документации PostgreSQL, это кажется допустимым (хотя в документах нет явных примеров), однако выполнение инструкции как с помощью pyscopg2, так и в редакторе запросов PostgreSQL приводит к этой синтаксической ошибке. Однако выполнение следующей инструкции в редакторе SQL PostgreSQL успешно:
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 правильно отформатировать запрос?
Комментарии:
1. Попробуйте преобразовать его в строку на Python и интерполировать ее.
2. @LaurenzAlbe Это должно сработать. Хотя мне любопытно знать, почему документы psycopg2 и документы postgresql указывают, что синтаксис допустим, несмотря на эту синтаксическую ошибку. Я пока оставлю этот вопрос открытым.
3. Синтаксис недопустим. Вам нужно указать константу, а не выражение, такое как приведение типа.
4. Причина в таблице Create : «Каждое из значений, указанных в параметре partition_bound_spec, является литеральным, НУЛЕВЫМ, МИНИМАЛЬНЫМ или МАКСИМАЛЬНЫМ ЗНАЧЕНИЕМ. Каждое литеральное значение должно быть либо числовой константой, которая сопоставима с типом соответствующего столбца ключа раздела, либо строковым литералом, который является допустимым вводом для этого типа. » Добавил это в качестве обновления к моему ответу.
Ответ №1:
Чтобы следить за комментарием @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(адаптация даты и времени), что вас раздражает.
Обновить
Согласно моему комментарию, причина, по которой это должен быть литерал, объясняется здесь Создать таблицу:
Каждое из значений, указанных в параметре partition_bound_spec, является литеральным, НУЛЕВЫМ, МИНИМАЛЬНЫМ или МАКСИМАЛЬНЫМ ЗНАЧЕНИЕМ. Каждое литеральное значение должно быть либо числовой константой, приведенной к типу соответствующего столбца ключа раздела, либо строковым литералом, который является допустимым вводом для этого типа.