Фрейм данных в базу данных PostgreSQL

#python #postgresql

Вопрос:

Я запрашиваю данные за 4 часа из исходной базы данных PLC MS SQL, обрабатываю их с помощью python и записываю данные в основную таблицу Postgresql.

При записи в основную таблицу Postgres ежечасно появляется дублирующее значение (предыдущие 3 часа) -это приведет к ошибке (первичный ключ) и предотвратит ошибку транзакции и python.

Так,

  1. Я создаю временную таблицу PostgreSQL без какого-либо ключа каждый раз ежечасно
  2. Затем скопируйте фрейм данных pandas во временную таблицу
  3. Затем вставьте строки из временной таблицы —gt; основная таблица PostgreSQL
  4. Отбросьте временную таблицу PostgreSQL

Этот скрипт на python запускается в планировщике задач Windows ежечасно

Ниже приведен мой запрос.

 engine = create_engine('postgresql://postgres:postgres@host:port/dbname?gssencmode=disable') conn = engine.raw_connection() cur = conn.cursor()  cur.execute("""CREATE TABLE public.table_temp (  datetime timestamp without time zone NOT NULL,  tagid text COLLATE pg_catalog."default" NOT NULL,  mc text COLLATE pg_catalog."default" NOT NULL,  value text COLLATE pg_catalog."default",  quality text COLLATE pg_catalog."default" )  TABLESPACE pg_default;  ALTER TABLE public.table_temp  OWNER to postgres;""");  output = io.StringIO() df.to_csv(output, sep='t', header=False, index=False) output.seek(0) contents = output.getvalue() cur.copy_from(output, 'table_temp', null="") cur.execute("""Insert into public.table_main select * From table_temp ON CONFLICT DO NOTHING;"""); cur.execute("""DROP TABLE table_temp CASCADE;"""); conn.commit()  

Я хотел бы знать, есть ли какой-либо эффективный/быстрый способ сделать это

Комментарии:

1. у фреймов данных (панд) есть to_sql() метод, который вам, возможно, не понадобится экспортировать в csv.

Ответ №1:

Если я прав, предполагая, что данные находятся во фрейме данных, вы должны просто уметь это делать

 engine = create_engine('postgresql://postgres:postgres@host:port/dbname?gssencmode=disable') df.drop_duplicates(subset=None) # Replace None with list of column names that define the primary key ex. ['column_name1', 'column_name2'] df.to_sql('table_main', engine, if_exists='append')  

Изменить из-за комментария:
Если это так, то у вас есть правильная идея. Вы можете сделать это более эффективным, используя to_sql, чтобы сначала вставить данные во временную таблицу, вот так.

 engine = create_engine('postgresql://postgres:postgres@host:port/dbname?gssencmode=disable') df.to_sql('table_temp', engine, if_exists='replace') cur.execute("""Insert into public.table_main select * From table_temp ON CONFLICT DO NOTHING;"""); # cur.execute("""DROP TABLE table_temp CASCADE;"""); # You can drop if you want to but the replace option in to_sql will drop and recreate the table conn.commit()  

Комментарии:

1. Предположим, мы запрашиваем данные за 4 часа, каждый час, скажем, данные с 5.00 до 9.00 и записываем их в основную таблицу postgresql в 9.05, в основной таблице уже будут данные (с 5.00 до 08.00) (предыдущие 3 часа), которые были сохранены в 7.05, 8.05 и т. Д. Я не хочу снова записывать (с 5.00 до 08.00) данные в основную таблицу и создавать несколько дубликатов. Таково мое намерение. Кроме того, вы можете спросить, почему я каждый раз получаю данные за 4 часа, это просто для безопасности. Потому что планировщик задач несколько раз пропускает какое-либо конкретное почасовое расписание python. Что может привести к потере этого часа. Спасибо!

2. В зависимости от того, как извлекаются данные, вы можете сохранить (возможно, вы можете получить их из table_main ) максимальную временную метку извлеченных данных и начать оттуда. Это позволит избежать захвата данных, которые вы уже захватили, и избежать пропуска каких-либо