psycopg2.sql Вставка типа переменной с использованием sql.Идентификатор приводит к типу «целое число», не существует

#python #psycopg2

#python #psycopg2

Вопрос:

Я пытаюсь динамически создавать таблицы с помощью psycopg2.sql, я написал функцию, которая принимает список кортежей, состоящий из имени столбца и типа данных столбца, затем я создаю строку, вызываю ее query, используя «{}» в качестве заполнителей, подобных этому:

 create table {} ({} {}, {} {} ...);
  

Я сглаживаю список кортежей, чтобы элементы в результирующем списке соответствовали порядку, в котором я хочу вставить их в строку запроса, и использую результирующий список в качестве аргумента в sql.SQL(query).format(…)

Результирующий экземпляр sql.Composed выглядит следующим образом:

 Composed([SQL('create table '), Identifier('games'), SQL(' ( '), Identifier('score_loser'), SQL(' '), Identifier('integer'), SQL(' , '), Identifier('playoffs'), SQL(' '), Identifier('boolean'), SQL(' , '), Identifier('record_loser'), SQL(' '), Identifier('integer[]'), SQL(' , '), Identifier('broadcast'), SQL(' '), Identifier('varchar(20)'), SQL(' , '), Identifier('date'), SQL(' '), Identifier('date'), SQL(' , '), Identifier('id'), SQL(' '), Identifier('varchar (30)'), SQL(' , '), Identifier('home_team'), SQL(' '), Identifier('varchar (50)'), SQL(' , '), Identifier('record_winner'), SQL(' '), Identifier('integer[]'), SQL(' , '), Identifier('winner'), SQL(' '), Identifier('varchar (50)'), SQL(' , '), Identifier('loser'), SQL(' '), Identifier('varchar (50)'), SQL(' , '), Identifier('score_winner'), SQL(' '), Identifier('integer'), SQL(' , primary key ('), Identifier('id'), SQL(') );')])
  

Но когда я пытаюсь выполнить этот экземпляр sql.Composed, я получаю сообщение об ошибке, что «integer» не является типом, где «integer» был элементом в списке, который я передал функции format.

Невозможно ли также динамически передавать типы переменных с помощью psycopg2.sql, или, если это возможно, не могли бы вы рассказать мне, как это сделать?

Ответ №1:

У меня была похожая проблема. Я решил это, смешав состав строк, format() и генераторы списков.

 data = (('column_name_1','VARCHAR(2)'), ('column_name_2','INT'))
data = ['%s %s' % (x[0], x[1]) for x in data]
columns_string = ', '.join([x for x in data])
  

Здесь columns_string =
имя_столбца 1 VARCHAR(2), имя_столбца 2 INT

 query = 'CREATE TABLE {}(%s)' % columns_string
query = sql.SQL(query).format(sql.Identifier('test_table'))
  

Если мы проверим запрос:

 print(query.as_string(conn))
  

СОЗДАЙТЕ ТАБЛИЦУ «test_table» (column_name_1 VARCHAR(2), column_name_2 INT)

Мы выполняем это как cur.execute(query) , и это работает. Не сложное и, вероятно, ненадежное решение, но работает.

Ответ №2:

У меня также было так много проблем с этим аспектом. sql.Identifier предназначен для двойных кавычек, ну, идентификаторов SQL, которые INTEGER не TEXT являются типами данных (, и т.д.). Похоже, что простое использование SQL делает свое дело.

Примечание В вашем коде вы должны иметь заранее определенные columns кортежи и не предоставлять их определение интерфейсу. Именно поэтому здесь полезны кортежи, поскольку они неизменяемы.

 import psycopg2.sql as sql

def create_table( name, columns ):
    # name = "mytable"
    # columns = (("col1", "TEXT"), ("col2", "INTEGER"), ...)
    fields = []
    for col in columns:
        fields.append( sql.SQL( "{} {}" ).format( sql.Identifier( col[0] ), sql.SQL( col[1] ) ) )

    query = sql.SQL( "CREATE TABLE {tbl_name} ( {fields} );" ).format(
        tbl_name = sql.Identifier( name ),
        fields = sql.SQL( ', ' ).join( fields )
    )
    print( query.as_string(conn) ) # CREATE TABLE "mytable" ( "col1" TEXT, "col2" INTEGER );
    # Get cursor and execute...