Форум программистов, компьютерный форум, киберфорум
PostgreSQL
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
6 / 6 / 0
Регистрация: 18.10.2017
Сообщений: 51

Триггерная функция БД

26.12.2019, 17:37. Показов 787. Ответов 2
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день.

Имею таблицы "Клиент", "Заказ", "Процесс заказа", "Услуга"

Клиент - "ID"(pk), "ФИО", "Критерий постоянства"

Заказ - "ID_Клиент"(fk), "Дата приёма", "Дата возврата", "ID"(pk)

Процесс заказа - "ID_Заказ"(pk fk), "ID_Услуга"(pk fk), "Срочность услуги", "Сложность услуги".

Услуга - "ID", "Длительность услуги".

Суть - При заполнении таблицы Заказ я заполняю всё кроме Даты возврата (она заполняется якобы при возврате, т.е. через время). Потом заполняю Процесс Заказа и прописываю входящие Услуги в Заказ, и срочные они или нет. Потом заполняю Дату возврата.

Суть триггеров:
1. При изменении Даты возврата - Если разница между датой возврата и датой приёма больше чем длительность услуги, то в таблице Процесс заказа Срочность устанавливаем в false
2. При изменении Срочности - Если дата возврата уже выставлена, соответственно менять срочность мы не имеем права, и Срочность менять нельзя.

Что сделал

Функция1 BEFORE UPDATE:

SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DECLARE 
    /*diff real;*/
    S REAL;
BEGIN
    IF (NEW."Дата_возврата" IS NOT NULL) THEN 
    SELECT
        (NEW."Дата_возврата"-OLD."Дата_приёма")*24 / "Услуга"."Длительность_услуги(в_часах)" INTO S
    FROM "Заказ" INNER JOIN "Процесс заказа" ON "Заказ"."Идентификатор" = "Процесс заказа"."Идентификатор_Заказ"
        INNER JOIN "Услуга" ON "Процесс заказа"."ID_Услуга" = "Услуга"."ID"
        WHERE ("Заказ"."Идентификатор" = NEW."Идентификатор");
        
        UPDATE "Процесс заказа"
        SET "Срочность" = CASE WHEN S>1.0 THEN FALSE ELSE "Процесс заказа"."Срочность" END 
        WHERE ("Процесс заказа"."Идентификатор_Заказ" = NEW."Идентификатор");
        RETURN NEW;
        ELSE RETURN OLD;
    END IF;
 
END;

Функция2 AFTER UPDATE:
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DECLARE 
    diff REAL;
BEGIN
    IF
    (
     SELECT
            "Дата_возврата" FROM "Заказ" INNER JOIN "Процесс заказа" 
            ON (NEW."Идентификатор_Заказ"  = "Заказ"."Идентификатор" )
            IN ("Процесс заказа"."Идентификатор_Заказ" = NEW."Идентификатор_Заказ")
    ) IS NOT NULL THEN 
        raise exception 'Ошибка при обновлении "Срочность" в таблице "Процесс заказа"!';
        RETURN OLD;
    ELSE
      RETURN NEW;
    END IF;
END;
Выбивает ошибку "подзапрос выдал больше одной строки" при срабатывании второй функции. Я понимаю, почему - потому что написанный селект должен выдавать одну строку, а выдаёт несколько (в одном Заказе м.б. несколько Услуг, которые надо проверить все и поменять Срочность или запретить). Как исправить, чтобы функция корректно проверяла все строки на NOT NULL?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.12.2019, 17:37
Ответы с готовыми решениями:

Триггерная функция
Есть две таблицы: clients и mailParties. Из программы выполняется batch, т.е. добавляются сразу две записи в clients. С помощью триггерной...

Триггер и триггерная функция таблицы
Есть таблицы "Клиент" и "Заказ". Клиент имеет поля "ID"(pk), "ФИО" и "Постоянство"(bool). Заказ имеет поля "Идентификатор"(pk),...

Функция поиска в массиве и указатели + функция сортировки и поиск найденного элемента
Написать функцию поиска максимального элемента, передать в неё указатель на начало и конец поиска и возвращать указатель на найденный...

2
1267 / 980 / 385
Регистрация: 02.09.2012
Сообщений: 3,027
26.12.2019, 21:24
1. Зачем вам JOIN с Процесс заказа при определении Дата_возврата. Уберите, тогда не будет дублирования. Вам же все равно через какой Процесс_заказа вы будете обращаться, они все показывают на один и тот же свой Заказ.
Тогда не будет множественного выбора.
2. Если хотите что-то запретить, то вам надо перейти к BEFORE триггеру и возвращать OLD. В AFTER триггере уже все случилось.
0
6 / 6 / 0
Регистрация: 18.10.2017
Сообщений: 51
27.12.2019, 04:34  [ТС]
1. Убрал, вышло так:
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DECLARE 
    /*diff real;*/
    S REAL;
BEGIN
    IF (NEW."Дата_возврата" IS NOT NULL) THEN 
    SELECT
        (NEW."Дата_возврата"-OLD."Дата_приёма")*24 / "Услуга"."Длительность_услуги(в_часах)" INTO S
    FROM "Заказ" INNER JOIN "Процесс заказа" ON "Заказ"."Идентификатор" = "Процесс заказа"."Идентификатор_Заказ"
        INNER JOIN "Услуга" ON "Процесс заказа"."ID_Услуга" = "Услуга"."ID"
        WHERE ("Заказ"."Идентификатор" = NEW."Идентификатор");
        
        UPDATE "Процесс заказа"
        SET "Срочность" = CASE WHEN S>1.0 THEN FALSE ELSE "Процесс заказа"."Срочность" END 
        WHERE ("Процесс заказа"."Идентификатор_Заказ" = NEW."Идентификатор");
        RETURN NEW;
        ELSE RETURN OLD;
    END IF;
 
END;
Но такой Select просто выводит все даты возвратов заказов, и соответственно ошибка повторяется. Выводится же должен только тот, Идентификатор которого написан в строке, изменяемой Триггером

Добавлено через 19 минут
Оставил так, ошибку выдавать перестало:
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
DECLARE 
    diff REAL;
BEGIN
    IF
    (
     SELECT
            "Дата_возврата" FROM "Заказ" WHERE ("Заказ"."Идентификатор" = NEW."Идентификатор_Заказ")
    ) IS NOT NULL THEN 
        raise exception 'Ошибка при обновлении "Срочность" в таблице "Процесс заказа"!';
        RETURN OLD;
    ELSE
      RETURN NEW;
    END IF;
END;
Но появилась другая проблема. Если в Заказе находятся, например, две услуги, обе срочные, и одна к Дате возврата успевает в срок, а вторая просрочивает Длительность услуги, соответственно, первую надо оставлять TRUE, а вторую FALSE. Но код который есть у меня меняет либо обе строки в TRUE, либо в FALSE, в зависимости от того, какая первая услуга была. Как исправить?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
27.12.2019, 04:34
Помогаю со студенческими работами здесь

Функция удаления текста в скобках [2], непосредственно функция + 12кб вложений
Доброго времени суток, случилось так, что пришлось работать с с-строками (лаба, угу), в которой нужно удалить весь текст в скобках,...

Перегрузка операций: friend-функция или функция-член класса
Здравствуйте, меня интересует вопрос, в чем разница при перегрузке операторов через operator и friend. Вот к примеру такой код. class...

Функция sqrt: существует более одного экземпляра. Функция перегруженная
#include <iostream> #include <math.h> #include <iomanip> using namespace std; int main(){ float s, p; int c, a; s=0; ...

Выясните, сохраняет ли булева функция 0, 1, является ли функция линейной, монотонной, само двойственной?
Помогите пожалуйста!!! Булева функция задана вектором значений F(x)=(1001) Выясните, сохраняет ли эта функция 0, 1, является ли эта...

Какую библиотеку надо подключать чтоб работала функция _getch() и функция cin.get()?
какую библиотеку надо подключать чтоб работала функция _getch() и функция cin.get()


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
3
Ответ Создать тему
Новые блоги и статьи
Доступность команды формы по условию
Maks 07.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: сделать доступной кнопку (команда формы "ЗавершитьСписание") при. . .
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru