#python #postgresql
Вопрос:
Я запрашиваю данные за 4 часа из исходной базы данных PLC MS SQL, обрабатываю их с помощью python и записываю данные в основную таблицу Postgresql.
При записи в основную таблицу Postgres ежечасно появляется дублирующее значение (предыдущие 3 часа) -это приведет к ошибке (первичный ключ) и предотвратит ошибку транзакции и python.
Так,
- Я создаю временную таблицу PostgreSQL без какого-либо ключа каждый раз ежечасно
- Затем скопируйте фрейм данных pandas во временную таблицу
- Затем вставьте строки из временной таблицы —gt; основная таблица PostgreSQL
- Отбросьте временную таблицу 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
) максимальную временную метку извлеченных данных и начать оттуда. Это позволит избежать захвата данных, которые вы уже захватили, и избежать пропуска каких-либо