Обработка данных в реальном времени в postgresql от pandas

#python #pandas #postgresql

Вопрос:

У меня есть 2 таблицы в PostgreSQL:-

  1. «студенческий» стол
 student_id name   score
1         Adam     10
2         Brian    9
 
  1. таблица «student_log» :-
 log_id student_id score
1         1       10
2         2       9
 

У меня есть скрипт на python, который извлекает фрейм данных со столбцами «имя» и «оценка», а затем заполняет его в таблице учащихся.

Я хочу обновлять таблицу student и student_log всякий раз, когда у студента меняется «оценка». Кроме того, если во фрейме данных есть новое имя учащегося, я хочу добавить для него еще одну строку в таблицу учащихся, а также сохранить ее запись в таблице «student_log». Кто-нибудь может подсказать, как это можно сделать?

Давайте рассмотрим новый извлеченный фрейм данных, который выглядит следующим образом:-

 name score
Adam  7
Lee   5
 

Тогда ожидаемый результат будет:-

«студенческий» стол

 student_id name   score
1         Adam     7
2         Brian    9
3         Lee      5
 

таблица «student_log» :-

 log_id student_id score
1         1       10
2         2       9
3         1       7    
4         3       5
 

Ответ №1:

Наконец-то я нашел хороший ответ. Я использовал триггер, функцию и CTE.

Я создаю функцию для регистрации изменений вместе с триггером для обработки обновлений. Ниже приведен код.

 CREATE OR REPLACE FUNCTION log_last_changes()
  RETURNS TRIGGER 
  LANGUAGE PLPGSQL
  AS
$
DECLARE
serial_num integer;
BEGIN
    IF NEW.name <> OLD.name OR NEW.score <> OLD.score
    THEN
         SELECT SETVAL('log_id_seq', (select max(id) from log)) into serial_num;
     INSERT INTO log(student_id,score)
     VALUES(NEW.id,NEW.score)
         ON CONFLICT DO NOTHING;
    END IF;
  RETURN NEW;
END;
$;

CREATE TRIGGER log_student
  AFTER UPDATE
  ON student
  FOR EACH ROW
  EXECUTE PROCEDURE log_last_changes();
 

Выражение CTE выглядит следующим образом:-

 WITH new_values(id, name, score) AS ( 
    values
        (1,'Adam',7),
        (2,'Brian',9),
        (3,'Lee',5)      
),
upsert AS 
    ( 
        UPDATE student s 
        SET NAME = nv.name,
        SCORE = nv.score
        FROM new_values nv, student s2
        WHERE 
            s.id = nv.id and s.id = s2.id 
        Returning s.* 
    )
    INSERT INTO student select id, name, score 
    FROM 
        new_values 
    WHERE NOT EXISTS (
            SELECT 1  from upsert up where up.id=new_values.id
    );
 

Ответ №2:

Я предполагаю, что вы пытаетесь различить два
кадра данных вот пример

 #old student dataframe
old_pd:pd.DataFrame

#new student dataframe
new_pd:pd.DataFrame

joined_pd = new_pd.join(old_pd,on='name',lsuffix='_new',rsuffix='_old')
diff_pd = joined_pd[joined_pd['score_new']!=joined_pd['score_old']]

#then insert all diff_pd to student_log table.and update to student table
 

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

1. Не могли бы вы, пожалуйста, подсказать, как это можно сделать непосредственно на PostgreSQL?

2. вы имеете в виду не использовать объединение фреймов данных.вместо прямого использования sql?

3. Да, используя Postgres напрямую.

4. при прямом использовании Postgres. Я рассмотрю возможность вставки новых данных во временную таблицу. затем используйте SQL-соединение,подзапрос, чтобы решить эту проблему