Вставка строк разной длины в Postgres с помощью pyscopg2 - PullRequest
0 голосов
/ 30 апреля 2019

Я строю несколько разных фреймов данных pandas в цикле for, у которых разное количество столбцов, в зависимости от того, какие данные доступны с веб-сайта, который я собираю.

Проблема, с которой я сталкиваюсь, заключается в том, что, когда я зацикливаюсь над строками кадра данных в конце начального цикла, чтобы вставить их в postgres, используя psycopg2, длина имен столбцов и количество строк меняются для каждогоцикл, то есть мне нужен динамический запрос.Заданное количество столбцов всегда будет там и будет иметь тип символа, а столбцы, которые могут / не могут быть, имеют тип числовой.

Это то, что я уже пробовал:

con = pypg.connect(user = pg_user, password = pg_pass,
                   host = "pg_host", database = "db",
                   port = "5432")

cursor = con.cursor()

# dt = pandas dataframe with n columns
cols = [i for i in dt.columns if i not in ["column1","column2","column3"]] 

# these columns are always in dt, want to convert others to numeric

for col in cols:
    dt[col]=pd.to_numeric(dt[col])

# Build the string insertion vectors for the correct number of columns
col_insert = "%s, %s, %s,"
data_insert = "%s, %s, %s,"

sql_colnames = tuple(dt.columns)

for i in range(1, (len(sql_colnames) - 2), 1):
  if i != (len(sql_colnames) - 3):
    data_insert = data_insert + " %d,"
    col_insert = col_insert + " %s,"
  elif i == (len(sql_colnames) - 3):
       data_insert = data_insert + " %d"
       col_insert = col_insert + " %s"

# Iterate through the rows of the dataframe and insert them into postgres
for index, row in all_odds_dt.iterrows():
    row_ = tuple(row)
    qry_data = sql_colnames + row_prices
    qry = "INSERT INTO odds_portal_prices (" + col_insert + ") VALUES(" + data_insert + ")" % qry_data

cursor.execute(qry)

Ошибка, которую я получаю при попытке выполнить запрос:

  File "<ipython-input-351-14d7e958b2a7>", line 4, in <module>
    qry = "INSERT INTO odds_portal_prices (" + col_insert + ") VALUES(" + data_insert + ")" % qry_data
TypeError: not all arguments converted during string formatting

Я проверил длину вектора qry_data, чтобы убедиться, что он совпадает с количеством элементов в col_insertи data_insert вместе взятых.

Заранее благодарим за любую помощь.

Ответы [ 2 ]

1 голос
/ 30 апреля 2019

С помощью параметризации вы можете оптимизировать большую часть обработки, не беспокоясь о строковом форматировании значений между строковым и числовым типами.Однако предпочтительный str.format используется для построения подготовленного оператора, но только один раз вне какого-либо цикла.

Примечание: заполнитель параметра для psycopg2 равен %s, что не следует путать с символами форматирования строки Python%s и %d.

### CONVERT NUMERIC COLUMNS WITH apply()
num_cols = dt.columns.difference(["column1","column2","column3"]).values
dt[num_cols] = dt[num_cols].apply(pd.to_numeric)

### BUILD PREPARED STATEMENT (NO DATA)
sql = ("INSERT INTO dbo.Employee_Photo ({sql_cols}) VALUES ({placeholders})"
         .format(sql_cols = ", ".join([i for i in dt.columns]), 
                 placeholders = ", ".join(["%s" for i in dt.columns]))
      )

# EXECUTE PARAMETERIZED QUERY BINDING DF VALUES
cursor.executemany(sql, dt.values.tolist())   
con.commit()
0 голосов
/ 30 апреля 2019

Ваша прямая и непосредственная проблема связана с тем, как ломается линия, на которой происходит ваше форматирование. Если я расширяю его, чтобы использовать некоторые временные переменные, это на самом деле происходит так:

qry1 = "INSERT INTO odds_portal_prices ("
qry2 = ") VALUES("
qry3 = ")" % qry_data
qry = qry1 + col_insert + qry2 + data_insert + qry3

Поскольку в строке нет точек форматирования ")" все аргументы форматирования не используются.

Однако , это не лучший способ динамического построения оператора SQL. Я бы рекомендовал сначала отделить построение оператора со столбцами от значений. Затем используйте аргумент vars для функции execute курсора, чтобы безопасно получить параметры в запросе. Для получения более подробной информации см. соответствующую документацию по psycopg .

...