Arrow
Arrow31 липня 2018 р. 04:57

Робота з тригерними функціями в PostgreSQL

У процесі розробки одного додатка для обліку норм часу виникла потреба у створенні зведеної таблиці з вибіркою даних із вже існуючої.

Як база даних використовувалася PostgreSQL.

Вихідна таблиця “base_table” спрощено має такий вигляд:

Поля таблиці мають такі типи:

  • id - ціле число, auto inc;
  • дата - дата;
  • кількість - ціле число;
  • hours_count - час

Іншим полям спрощено надано тип text .

Спрощення введені, щоб не загострювати увагу на структурі таблиці.


З неї в зведену таблицю «new_table» необхідно вибрати такі дані: order, equipment, product, SUM(quantity), SUM(hours_count) , також у зведеній таблиці повинні бути наступні поля data (integer ) та state (boolean) . У нову таблицю необхідно вносити не просто значення зі стовпців order, equipment, product, а згруповані.

Для простоти розуміння, забігаючи трохи наперед, наведу гаданий код запиту, що задовольняє поставлене завдання:

INSERT INTO new _table ( order , equip ment , p roduct , o quantity , time_sum )
SELECT order_number , equipment , p roduct , SUM ( quantity ), SUM ( hours_count )
FROM base _table GROUP BY order , equipment , p roduct
HAVING NOT EXISTS ( SELECT order , equip ment , p roduct FROM new _table WHERE order = order AND equip ment = equipment AND p roduct = p roduct );

Спочатку були думки з приводу створення окремої таблиці “new_table” як зведеної та в ручному режимі у програмі використовує базу даних за допомогою SQL запиту здійснювати вибірку необхідних даних з основної таблиці. Але все ж таки залишалося питання як бути при створенні нових записів в "base_table" після здійснення вибірки, так як дані будуть вноситись безперервно і їх необхідно постійно оновлювати і в "new_table" .

Після обговорення на форумі сайту EVILEG можливих варіантів вирішення поставленого завдання, його творцем був запропонований варіант виходу із ситуації шляхом реакції на зміни даних в основній таблиці.

Виходячи з цього, було прийнято рішення про необхідність синхронізації даних у таблицях так, щоб при створенні, редагуванні або видаленні записів у “base_table” відповідні зміни відбувалися і у зведеній таблиці “new_table” .

Вигляд таблиці “new_table” :

Стало ясно, що для цього необхідно використовувати тригерні функції для обробки подій створення, редагування та видалення даних з базової таблиці.

Перейдемо до розгляду процесу створення такої функції із її описом.

Нижче вказано оголошення тригерної функції:

CREATE TRIGGER select_to_table
BEFORE INSERT OR UPDATE OR DELETE ON base _table
FOR ROW EXECUTE PROCEDURE process_select_to ();

У першому рядку вказано оголошення функції, назвемо її «select_to_table» .

У другому рядку зазначено під час виконання яких дій над базовою таблицею функція має бути викликана. Ключове слово BEFORE означає, що функцію необхідно викликати до створення нового запису ( INSERT ), редагування ( UPDATE ) або видалення наявного запису ( DELETE ) у таблиці “base_table” .

Замість BEFORE можна вказувати AFTER, що означає виклик функції після настання вище зазначених подій.

Варто зазначити, що офіційна документація PostgreSQL рекомендує використовувати як ключове слово BEFORE .

У третьому рядку вказується FOR ROW, або FOR EACH ROW. Перший запис означає виклик функції для одного рядка, а другий - по черговий для кожного рядка таблиці.

І останнім параметром після ключового слова PROCEDURE вказується ім'я функції, що викликається. Функція з цим іменем повинна бути описана перед оголошенням або вже існувати, інакше це викликає помилку.

Тепер перейдемо до загального вигляду самої функції.

CREATE OR REPLACE FUNCTION «имя функции»
RETURNS TRIGGER AS
$select_to$
BEGIN
-- тело функции --



RETURN NULL ; -- тип возвращаемого значения
END ;
$select_to$ LANGUAGE plpgsql;

Функція повинна мати вище наведений вигляд з обов'язковою вказівкою значення, що повертається. Як тип повертається значення вказаний NULL , так як тригер не виконує жодних дій над таблицями. Вся робота над таблицями відбуватиметься у тілі функції.

Вигляд функції особливих питань викликати ні. Тим не менше, всі зацікавлені в більш детальному описі можуть звернутися до офіційної документації.

Тепер перейдемо до написання тіла. Оскільки ми вказали раніше, що хочемо обробляти події INSERT, UPDATE та DELETE нам необхідно передбачити реакцію на кожну з них. Для визначення типу операції в PostgreSQL існує змінна TG_OP , в якій міститься ім'я виконуваної операції.

Виходячи з цього напишемо умову перевірки типу операції, яка матиме такий вигляд:

IF ( TG_OP = 'DELETE' ) THEN

-- операторы --

ELSEIF ( TG_OP = 'INSERT' ) THEN

-- операторы --

ELSIF ( TG_OP = 'UPDATE' ) THEN

-- операторы --

END IF ;

Тепер напишемо код для видалення запису:

IF ( TG_OP = 'DELETE' ) THEN

-- Удаление записи из таблицы new _table , которая удовлетворяет условию --
DELETE FROM new _table WHERE order = OLD . order AND product = OLD . product AND equipment = OLD . equipment ;
IF NOT FOUND THEN

RETURN NULL ; -- если строки в new _table не существует --

END IF ;
RETURN OLD ;

Думаю цей запит докладний опис не потребує, крім одного моменту - це ключове слово OLD , яке дає можливість дізнатися старі значення записів з таблиці “base_table” , тобто до їх зміни. Також необхідно відзначити, що функції видалення записів в якості повертається значення завжди повинно бути вказано RETURN OLD .

Перейдемо до створення нового запису:

ELSEIF ( TG_OP = 'INSERT' ) THEN

-- Создание новой записи в таблице new _table - -
INSERT INTO new _table ( order , equipme nt , p roduct , quantity , time_sum VALUES ( NEW . order_number , NEW . equipment , NEW . part , NEW . otk , NEW . hours_count );

RETURN NEW ;

Сам запит докладного опису також не потребує. Скажу тільки, що використовуючи слово NEW можливо отримати нові значення записів з таблиці “base_table” , а також, що як значення, що повертається при створенні або редагуванні записів необхідно вказувати як повертається значення NEW .

Тепер настала черга для оновлення запису:

ELSIF ( TG_OP = 'UPDATE' ) THEN

-- Обновление записи в new _table --
UPDATE new _table SET order = NEW . order , equip ment = NEW . equipment , p roduct = NEW . p roduct , quantity = NEW . quantity , time_sum = NEW . hours_count

WHERE order = OLD . order AND equip ment = OLD . equipment AND p roduct = OLD . p roduct AND quantity = OLD . quantity AND time_sum = OLD . hours_count ;
RETURN NEW ;

За цим запитом все має бути зрозуміло з попередніх описів. Тепер настав час подивитися на код цілком.

CREATE OR REPLACE FUNCTION «имя функции»
RETURNS TRIGGER AS
$select_to$
BEGIN
IF ( TG_OP = 'DELETE' ) THEN

-- Удаление записи из new _table , которая удовлетворяет условию
DELETE FROM new _table WHERE order = OLD . order AND product = OLD . product AND equipment = OLD . equipment ;
IF NOT FOUND THEN

RETURN NULL ; -- если строки в new _table не существует

END IF ;
RETURN OLD ;

ELSEIF ( TG_OP = 'INSERT' ) THEN

-- C оздание новой записи в new _table
INSERT INTO new _table ( order , equipme nt , p roduct , quantity , time_sum ) VALUES ( NEW . order_number , NEW . equipment ,

NEW . part , NEW . otk , NEW . hours_count );
RETURN NEW ;

ELSIF ( TG_OP = 'UPDATE' ) THEN

-- Обновление записи в new _table
UPDATE new _table SET order = NEW . order , equip ment = NEW . equipment , p roduct = NEW . p roduct ,

quantity = NEW . quantity , time_sum = NEW . hours_count
WHERE order = OLD . order AND equip ment = OLD . equipment AND p roduct = OLD . p roduct AND

quantity = OLD . quantity AND time_sum = OLD . hours_count ;
RETURN NEW ;

RETURN NULL ;
END ;
$select_to$ LANGUAGE plpgsql;



CREATE TRIGGER select_to_table
BEFORE INSERT OR UPDATE OR DELETE ON base _table
FOR ROW EXECUTE PROCEDURE process_select_to ();

Після виконання цього коду в базі даних PostgreSQL буде зареєстрована нова функція тригера для обробки створення, зміни або видалення записів в “base_table”. Синхронно аналогічні операції будуть виконуватися і з відповідними записами “new_table” .

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

A
  • 10 серпня 2018 р. 09:40

Приветствую!

Если вы создаете новую таблицу, почему бы просто не сделать вьюху ? Просто от одного названия "триггер" как-то не хочется его использовать, а уж кода сколько писать...

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
OI
  • Ora Iro
  • 24 грудня 2024 р. 06:38

C++ - Тест 001. Первая программа и типы данных

  • Результат:40бали,
  • Рейтинг балів-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Donald Randolph
Donald Randolph30 грудня 2024 р. 02:59
Personal Injury lawyer Santa Monica As an experienced Santa Monica personal injury lawyer, Donald C. Randolph has recovered over $100 Million in verdicts and settlements for our clients. In severe injury cases, this compensation i…
Nirvana Yoga School
Nirvana Yoga School30 грудня 2024 р. 05:13
OAuth2.0 через VK, получение email Nirvana Yoga School is one of the most trusted and reputed traditional Rishikesh yoga courses , India certified by Yoga Alliance, USA. We aim to spread traditional yoga teachings so t…
s
sripark30 грудня 2024 р. 04:47
Mobile app development company in Chennai A Mobile app development company in Chennai focuses on creating personalized mobile applications to meet various business requirements. These companies offer a full range of services,…
a
amit8830 грудня 2024 р. 04:45
Excel in Exams with PSLE Maths Tuition Singapore Preparing for the PSLE can be challenging, but the right guidance makes all the difference. PSLE Maths tuition Singapore offers personalized coaching to help students master key concepts, improv…
a
awinash6230 грудня 2024 р. 04:23
Unlock Your Potential with the Certified Public Accountant Credential" Becoming a Certified Public Accountant (CPA) is a career milestone that opens doors to unparalleled opportunities in the world of accounting and finance. This globally recognized qualification s…

Слідкуйте за нами в соціальних мережах