Гость
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Триггер на представление / 18 сообщений из 18, страница 1 из 1
11.05.2021, 19:07
    #40069435
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Добрый день!

Мне необходимо создать составной триггер, чтобы сделать представление редактируемым.
Создаю представление ("Last_Name", "First_Name", "Salary") на таблицу Employees ("Salary" имеет формат - "число$").

Но возникают проблемы:
1) Почему-то не обрабатываются ситуации в разделе Исключений в WHEN OTHERS. Например, если пытаюсь вставить больше, чем три столбца.
2) При выполнении любого UPDATE возникает исключение о том, что значение фамилии не должно быть NULL.

Вот код:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
create or replace TRIGGER edit_view_trg FOR
    INSERT OR UPDATE OR DELETE ON my_view
COMPOUND TRIGGER
    TYPE r_flags IS RECORD (
        v_last_name BOOLEAN,
        v_first_name BOOLEAN,
        v_salary BOOLEAN
    );

    TYPE r_view IS RECORD (
        v_last_name my_view."Last_Name"%TYPE,
        v_first_name my_view."First_Name"%TYPE,
        v_salary my_view."Salary"%TYPE
    );

    r_new r_view;
    r_old r_view;
    flags r_flags;
    v_empid employees.employee_id%TYPE;

    null_last_name EXCEPTION;
    wrong_salary EXCEPTION;

    -- Функция проверки зарплаты
    FUNCTION check_sal (
        sal VARCHAR2
    ) RETURN BOOLEAN IS
    BEGIN
        IF to_number(
            regexp_substr(
                substr(
                    sal,1,
                    length(sal) - 1),
                    '^[[:digit:]]+$'
                )
            ) IS NULL
        THEN RETURN FALSE;

        ELSIF
            substr(
                sal,
                length(sal),1
            ) != '$'
        THEN RETURN FALSE;

        ELSIF to_number(
                substr(
                    sal,1,
                    length(sal) - 1
                )
            ) <= 0
        THEN RETURN FALSE;
        END IF;

        RETURN TRUE;
    END check_sal;

    -- Процедура вставки
    PROCEDURE view_insert (
        r_new r_view
    ) IS
    BEGIN
        --определяем номер работника
        SELECT MAX(employee_id) + 1
        INTO v_empid
        FROM employees;

        IF r_new.v_last_name IS NULL
        THEN RAISE null_last_name;

        ELSE
            --з/п должно быть в формате 'натуральное_число$'
            IF check_sal(r_new.v_salary) --= TRUE AND check_email(upper(substr(r_new.v_first_name,1,1) || substr(replace(r_new.v_last_name,' ',''),1,7) )) = TRUE
            THEN
                INSERT INTO employees (
                    employee_id, first_name,
                    last_name, email,
                    phone_number, hire_date,
                    job_id, salary,
                    commission_pct, manager_id,
                    department_id
                ) VALUES (
                    v_empid,
                    initcap(r_new.v_first_name),
                    initcap(r_new.v_last_name),
                    upper(substr(r_new.v_first_name,1,1)
                    || substr(replace(r_new.v_last_name,' ',''),1,7) ),
                    NULL, SYSDATE, 'SA_REP',
                    substr(r_new.v_salary,1,length(r_new.v_salary) - 1),
                    NULL, NULL, NULL
                );

            ELSIF r_new.v_salary IS NULL THEN
                INSERT INTO employees (
                    employee_id, first_name,
                    last_name, email,
                    phone_number, hire_date,
                    job_id, salary,
                    commission_pct, manager_id,
                    department_id
                ) VALUES (
                    v_empid,
                    initcap(r_new.v_first_name),
                    initcap(r_new.v_last_name),
                    upper(substr(r_new.v_first_name,1,1)
                    || substr(replace(r_new.v_last_name,' ',''),1,7) ),
                    NULL, SYSDATE, 'SA_REP', r_new.v_salary,
                    NULL, NULL, NULL
                );

            ELSE RAISE wrong_salary;

            END IF;
        END IF;
    END view_insert;

    -- Процедура удаления
    PROCEDURE view_delete (
        r_old r_view
    ) IS
    BEGIN
        DELETE FROM employees
        WHERE last_name = initcap(r_old.v_last_name)
        AND first_name = initcap(r_old.v_first_name);

        UPDATE employees
        SET manager_id = NULL
        WHERE manager_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );

        DELETE FROM job_history
        WHERE employee_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );

        UPDATE departments
        SET manager_id = NULL
        WHERE manager_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );
    END view_delete;

    -- Процедура обновления
    PROCEDURE view_update (
        r_new r_view,
        r_old r_view,
        flags r_flags
    ) IS
        r_change r_view;
    BEGIN
        IF (flags.v_salary)
        THEN
            IF (check_sal(r_new.v_salary))
            THEN
                UPDATE employees
                SET salary = to_number(
                    regexp_substr(
                        substr(
                            r_new.v_salary,1,
                            length(r_new.v_salary) - 1
                        ),'^[[:digit:]]+$'
                    )
                )
                WHERE last_name = initcap(r_old.v_last_name)
                AND first_name = initcap(r_old.v_first_name);
            ELSE RAISE wrong_salary;
            END IF;
        END IF;
        
        IF (flags.v_last_name) AND (r_new.v_last_name IS NOT NULL)
        THEN
            UPDATE employees
            SET last_name = initcap(r_new.v_last_name)
            WHERE first_name = initcap(r_new.v_first_name)
            AND last_name = initcap(r_old.v_last_name);

            UPDATE employees
            SET email = upper(substr(r_new.v_first_name,1,1)
                || substr(replace(r_new.v_last_name,' ',''),1,7))
            WHERE first_name = initcap(r_old.v_first_name)
            AND last_name = initcap(r_old.v_last_name);
        ELSE RAISE null_last_name;
        END IF;
        
        IF (flags.v_first_name)
        THEN
            UPDATE employees
            SET first_name = initcap(r_new.v_first_name)
            WHERE first_name = initcap(r_old.v_first_name)
            AND last_name = initcap(r_old.v_last_name);
        END IF;

    END view_update;

    INSTEAD OF EACH ROW IS BEGIN
        r_new.v_last_name := :new."Last_Name";
        r_new.v_first_name := :new."First_Name";
        r_new.v_salary := :new."Salary";
        r_old.v_last_name := :old."Last_Name";
        r_old.v_first_name := :old."First_Name";
        r_old.v_salary := :old."Salary";

        IF (r_new.v_last_name != r_old.v_last_name)
        THEN flags.v_last_name := true;
        ELSE flags.v_last_name := false;
        END IF;

        IF (r_new.v_first_name != r_old.v_first_name)
        THEN flags.v_first_name := true;
        ELSE flags.v_first_name := false;
        END IF;

        IF (r_new.v_salary != r_old.v_salary)
        THEN flags.v_salary := true;
        ELSE flags.v_salary := false;
        END IF;

        IF inserting THEN
            view_insert(r_new);
        ELSIF updating THEN
            view_update(r_new,r_old,flags);
        ELSIF deleting THEN
            view_delete(r_old);
        END IF;

    EXCEPTION
        WHEN wrong_salary THEN
            raise_application_error(-20501, 'Неверное значение зарплаты для вставки');

        WHEN null_last_name THEN
            raise_application_error(-20502, 'Фамилия не может принимать NULL значение');

        WHEN dup_val_on_index THEN
            raise_application_error(-20503, 'Нарушено ограничение уникальности email');

        WHEN OTHERS THEN
             
            DBMS_OUTPUT.PUT_LINE('Некорректные данные');
    END INSTEAD OF EACH ROW;
END edit_view_trg;



Помогите, пожалуйста, разобраться.
...
Рейтинг: 0 / 0
11.05.2021, 19:09
    #40069437
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
В Employees тип данных salary - Number, email имеет ограничение - 8 символов.
...
Рейтинг: 0 / 0
13.05.2021, 00:19
    #40069807
Правильный Вася
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
А где код создания таблицы и вьюхи?
...
Рейтинг: 0 / 0
13.05.2021, 11:41
    #40069934
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Представление:
Код: plsql
1.
2.
3.
4.
CREATE VIEW my_view AS
SELECT 
UPPER(last_name) AS "Last_Name", NVL(UPPER(first_name), ' ') AS "First_Name", TO_CHAR(NVL(salary, 0) || '$') AS "Salary"
FROM employees;
...
Рейтинг: 0 / 0
13.05.2021, 11:52
    #40069937
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
С этими проблемами удалось разобраться: надо было проверку фамилии на null перенести в отдельный IF.

Но возникла еще одна проблема. Пытаюсь произвести обновление з/п следующим образом:

Код: plsql
1.
2.
UPDATE my_view
SET "Salary" = "Salary" + '1000$';



Обрабатываю новое значение как 'число$+число$', избавившись от знака доллара и преобразовав подстроки в числа, но возникает мое исключение.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
create or replace TRIGGER edit_view_trg FOR
    INSERT OR UPDATE OR DELETE ON my_view
COMPOUND TRIGGER
    TYPE r_flags IS RECORD (
        v_last_name BOOLEAN,
        v_first_name BOOLEAN,
        v_salary BOOLEAN
    );

    TYPE r_view IS RECORD (
        v_last_name my_view."Last_Name"%TYPE,
        v_first_name my_view."First_Name"%TYPE,
        v_salary my_view."Salary"%TYPE
    );

    r_new r_view;
    r_old r_view;
    flags r_flags;
    v_empid employees.employee_id%TYPE;

    null_last_name EXCEPTION;
    wrong_salary EXCEPTION;

    -- Функция проверки зарплаты
    FUNCTION check_sal (
        sal VARCHAR2
    ) RETURN BOOLEAN IS
    BEGIN
        IF to_number(
        to_number(regexp_substr(regexp_substr(replace(substr(sal,1,length(sal) - 1), '$',''),'^[[:digit:]]+[+][:digit:]]+'),'[[:digit:]]+')) + 
        to_number(regexp_substr(replace(substr(sal,1,length(sal) - 1), '$',''),'^[[:digit:]]+[+][:digit:]]+') , 
        length(regexp_substr(regexp_substr(replace(substr(sal,1,length(sal) - 1), '$',''),'^[[:digit:]]+[+][:digit:]]+'),'[[:digit:]]+'))+1
        )
        )
        IS NULL
        THEN RETURN FALSE;

        ELSIF
            substr(
                sal,
                length(sal),1
            ) != '$'
        THEN RETURN FALSE;

        ELSIF to_number(
                substr(
                    sal,1,
                    length(sal) - 1
                )
            ) <= 0
        THEN RETURN FALSE;
        END IF;
        
        RETURN TRUE;
    END check_sal;

    -- Процедура вставки
    PROCEDURE view_insert (
        r_new r_view
    ) IS
    BEGIN
        --определяем номер работника
        SELECT MAX(employee_id) + 1
        INTO v_empid
        FROM employees;

        IF r_new.v_last_name IS NULL
        THEN RAISE null_last_name;

        ELSE
            --з/п должно быть в формате 'число$'
            IF check_sal(r_new.v_salary)
            THEN
                INSERT INTO employees (
                    employee_id, first_name,
                    last_name, email,
                    phone_number, hire_date,
                    job_id, salary,
                    commission_pct, manager_id,
                    department_id
                ) VALUES (
                    v_empid,
                    initcap(r_new.v_first_name),
                    initcap(r_new.v_last_name),
                    upper(substr(r_new.v_first_name,1,1)
                    || substr(replace(r_new.v_last_name,' ',''),1,7) ),
                    NULL, SYSDATE, 'SA_REP',
                    substr(r_new.v_salary,1,length(r_new.v_salary) - 1),
                    NULL, NULL, NULL
                );

            ELSIF r_new.v_salary IS NULL THEN
                INSERT INTO employees (
                    employee_id, first_name,
                    last_name, email,
                    phone_number, hire_date,
                    job_id, salary,
                    commission_pct, manager_id,
                    department_id
                ) VALUES (
                    v_empid,
                    initcap(r_new.v_first_name),
                    initcap(r_new.v_last_name),
                    upper(substr(r_new.v_first_name,1,1)
                    || substr(replace(r_new.v_last_name,' ',''),1,7) ),
                    NULL, SYSDATE, 'SA_REP', r_new.v_salary,
                    NULL, NULL, NULL
                );

            ELSE RAISE wrong_salary;

            END IF;
        END IF;
    END view_insert;

    -- Процедура удаления
    PROCEDURE view_delete (
        r_old r_view
    ) IS
    BEGIN

        UPDATE departments
        SET manager_id = NULL
        WHERE manager_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );

        UPDATE employees
        SET manager_id = NULL
        WHERE manager_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );

        DELETE FROM job_history
        WHERE employee_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );

        DELETE FROM employees
        WHERE last_name = initcap(r_old.v_last_name)
        AND first_name = initcap(r_old.v_first_name);
    END view_delete;

    -- Процедура обновления
    PROCEDURE view_update (
        r_new r_view,
        r_old r_view,
        flags r_flags
    ) IS
        r_change r_view;
    BEGIN
        IF (flags.v_salary)
        THEN
            IF (check_sal(r_new.v_salary))
            THEN
             UPDATE employees
                SET salary =to_number(
        to_number(regexp_substr(regexp_substr(replace(substr(r_new.v_salary,1,length(r_new.v_salary) - 1), '$',''),'^[[:digit:]]+[+][:digit:]]+'),'[[:digit:]]+')) + 
        to_number(regexp_substr(replace(substr(r_new.v_salary,1,length( r_new.v_salary) - 1), '$',''),'^[[:digit:]]+[+][:digit:]]+') , 
        length(regexp_substr(regexp_substr(replace(substr(sal,1,length( r_new.v_salary) - 1), '$',''),'^[[:digit:]]+[+][:digit:]]+'),'[[:digit:]]+'))+1
        )
        ) 
            /*
                UPDATE employees
                SET salary = to_number(
                    regexp_substr(
                        substr(
                            r_new.v_salary,1,
                            length(r_new.v_salary) - 1
                        ),'^[[:digit:]]+$'
                    )
                )*/
                WHERE last_name = initcap(r_old.v_last_name)
                AND first_name = initcap(r_old.v_first_name);
                
            ELSE RAISE wrong_salary;
            END IF;
        END IF;

        IF (flags.v_last_name) THEN
        IF (r_new.v_last_name IS NOT NULL) THEN
            UPDATE employees
            SET last_name = initcap(r_new.v_last_name)
            WHERE first_name = initcap(r_new.v_first_name)
            AND last_name = initcap(r_old.v_last_name);

            UPDATE employees
            SET email = upper(substr(r_new.v_first_name,1,1)
                || substr(replace(r_new.v_last_name,' ',''),1,7))
            WHERE first_name = initcap(r_old.v_first_name)
            AND last_name = initcap(r_old.v_last_name);
        ELSE RAISE null_last_name;
        END IF;
        END IF;

        IF (flags.v_first_name)
        THEN
            UPDATE employees
            SET first_name = initcap(r_new.v_first_name)
            WHERE first_name = initcap(r_old.v_first_name)
            AND last_name = initcap(r_old.v_last_name);
        END IF;

    END view_update;

    INSTEAD OF EACH ROW IS BEGIN
        r_new.v_last_name := :new."Last_Name";
        r_new.v_first_name := :new."First_Name";
        r_new.v_salary := :new."Salary";
        r_old.v_last_name := :old."Last_Name";
        r_old.v_first_name := :old."First_Name";
        r_old.v_salary := :old."Salary";

        IF (r_new.v_last_name != r_old.v_last_name)
        THEN flags.v_last_name := true;
        ELSE flags.v_last_name := false;
        END IF;

        IF (r_new.v_first_name != r_old.v_first_name)
        THEN flags.v_first_name := true;
        ELSE flags.v_first_name := false;
        END IF;

        IF (r_new.v_salary != r_old.v_salary)
        THEN flags.v_salary := true;
        ELSE flags.v_salary := false;
        END IF;

        IF inserting THEN
            view_insert(r_new);
        ELSIF updating THEN
            view_update(r_new,r_old,flags);
        ELSIF deleting THEN
            view_delete(r_old);
        END IF;

    EXCEPTION
        WHEN wrong_salary THEN
            raise_application_error(-20501, 'Неверное значение з/п!');

        WHEN null_last_name THEN
            raise_application_error(-20502, 'Фамилия не может быть пустая!');

        WHEN dup_val_on_index THEN
            raise_application_error(-20503, 'Нарушено ограничение уникальности!');

    END INSTEAD OF EACH ROW;
END edit_view_trg ;



Как это исправить?
...
Рейтинг: 0 / 0
13.05.2021, 11:55
    #40069940
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stravicki,

Код: plsql
1.
2.
3.
4.
        --определяем номер работника
        SELECT MAX(employee_id) + 1
        INTO v_empid
        FROM employees;


если employee_id в триггере не переопределяется,
то в не однопользовательской среде, ето "неправильно" (рано или поздно выстрелит)

ps
удалять надо сначала с подчиненных таблиц

.....
stax
...
Рейтинг: 0 / 0
13.05.2021, 12:08
    #40069943
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stax,

Спасибо!
А не подскажите, в чем может быть проблема с обновлением зарплаты по типу "Salary" = "Salary" + '8000$'?
...
Рейтинг: 0 / 0
13.05.2021, 12:20
    #40069950
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stravicki
Stax,

Спасибо!
А не подскажите, в чем может быть проблема с обновлением зарплаты по типу "Salary" = "Salary" + '8000$'?


не понял про +8000

приведите пример update my_view когда надо увеличивать ЗП?


зы
я невнимательно (мельком) смотрел Ваш триггер

.....
stax
...
Рейтинг: 0 / 0
13.05.2021, 12:29
    #40069956
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stax,

Например,

Код: plsql
1.
2.
3.
UPDATE my_view
SET "Salary" = "Salary" ||'+'|| '8000$'
WHERE "Last_Name" = 'PETROV'; -- их может быть несколько



Здесь проблема в том, что надо обновить з/п на какое-то число (а не установить новое значение). Но в представлении столбец "Salary" строкового типа, поэтому надо строку разбить на подстроки и, преобразовав в числа (удалив символы $), сложить.
...
Рейтинг: 0 / 0
13.05.2021, 12:42
    #40069958
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stravicki,

ясно
будет напр "Salary * 1,2' или "Salary + 5%'

пишете анализатор формулы, а дальше
1) if/case
2) динамический sql
3) запретить формулы (меняем четко на значение)

.....
stax
...
Рейтинг: 0 / 0
13.05.2021, 16:31
    #40070052
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stax,

Написал функцию analyze_salary, но возникает ошибка в разделе RETURN: 'PLS-00306: ошибочно число или типы аргументов при обращении к 'TO_NUMBER''. Но в чем проблема не вижу.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
create or replace TRIGGER edit_view_trg FOR
    INSERT OR UPDATE OR DELETE ON my_view
COMPOUND TRIGGER
    TYPE r_flags IS RECORD (
        v_last_name BOOLEAN,
        v_first_name BOOLEAN,
        v_salary BOOLEAN
    );

    TYPE r_view IS RECORD (
        v_last_name my_view."Last_Name"%TYPE,
        v_first_name my_view."First_Name"%TYPE,
        v_salary my_view."Salary"%TYPE
    );

    r_new r_view;
    r_old r_view;
    flags r_flags;
    v_empid employees.employee_id%TYPE;

    null_last_name EXCEPTION;
    wrong_salary EXCEPTION;

    -- Функция проверки з/п
    FUNCTION check_sal (
        sal VARCHAR2
    ) RETURN BOOLEAN IS
    BEGIN
        IF to_number(
            regexp_substr(
                substr(
                    sal,1,
                    length(sal) - 1),
                    '^[[:digit:]]+$'
                )
            ) IS NULL
        THEN RETURN FALSE;

        ELSIF
            substr(
                sal,
                length(sal),1
            ) != '$'
        THEN RETURN FALSE;

        ELSIF to_number(
                substr(
                    sal,1,
                    length(sal) - 1
                )
            ) <= 0
        THEN RETURN FALSE;
        END IF;

        RETURN TRUE;
    END check_sal;
    
    FUNCTION analyze_salary (
        sal VARCHAR2
    ) RETURN NUMBER IS
    BEGIN
        IF regexp_instr(sal, '[+]') > 0 THEN
        RETURN to_number(regexp_substr(sal, '^[[:digit:]]+')) + to_number(replace(substr(sal,length(regexp_substr(sal, '[[:digit:]]+'))+3),'$', '')); -- первое число + второе число
        ELSIF regexp_instr(sal, '[-]') > 0 THEN
        RETURN to_number(regexp_substr(sal, '^[[:digit:]]+')) - to_number(replace(substr(sal,length(regexp_substr(sal, '[[:digit:]]+'))+3),'$', '')); -- первое число - второе число
        ELSIF check_sal(sal) = TRUE THEN
        RETURN to_number(check_sal(sal));
        END IF;
    END analyze_salary;
    -- Процедура вставки
    PROCEDURE view_insert (
        r_new r_view
    ) IS
    BEGIN
        --определяем номер работника
        SELECT MAX(employee_id) + 1
        INTO v_empid
        FROM employees;

        IF r_new.v_last_name IS NULL
        THEN RAISE null_last_name;

        ELSE
            --з/п должно быть в формате 'число$'
            IF check_sal(r_new.v_salary)
            THEN
                INSERT INTO employees (
                    employee_id, first_name,
                    last_name, email,
                    phone_number, hire_date,
                    job_id, salary,
                    commission_pct, manager_id,
                    department_id
                ) VALUES (
                    v_empid,
                    initcap(r_new.v_first_name),
                    initcap(r_new.v_last_name),
                    upper(substr(r_new.v_first_name,1,1)
                    || substr(replace(r_new.v_last_name,' ',''),1,7) ),
                    NULL, SYSDATE, 'SA_REP',
                    substr(r_new.v_salary,1,length(r_new.v_salary) - 1),
                    NULL, NULL, NULL
                );

            ELSIF r_new.v_salary IS NULL THEN
                INSERT INTO employees (
                    employee_id, first_name,
                    last_name, email,
                    phone_number, hire_date,
                    job_id, salary,
                    commission_pct, manager_id,
                    department_id
                ) VALUES (
                    v_empid,
                    initcap(r_new.v_first_name),
                    initcap(r_new.v_last_name),
                    upper(substr(r_new.v_first_name,1,1)
                    || substr(replace(r_new.v_last_name,' ',''),1,7) ),
                    NULL, SYSDATE, 'SA_REP', r_new.v_salary,
                    NULL, NULL, NULL
                );

            ELSE RAISE wrong_salary;

            END IF;
        END IF;
    END view_insert;
    
    -- Процедура удаления
    PROCEDURE view_delete (
        r_old r_view
    ) IS
    BEGIN
        DELETE FROM job_history
        WHERE employee_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );
        
        UPDATE departments
        SET manager_id = NULL
        WHERE manager_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );
        
        UPDATE employees
        SET manager_id = NULL
        WHERE manager_id = (
            SELECT employee_id
            FROM employees
            WHERE last_name = initcap(r_old.v_last_name)
            AND first_name = initcap(r_old.v_first_name)
        );
         
        DELETE FROM employees
        WHERE last_name = initcap(r_old.v_last_name)
        AND first_name = initcap(r_old.v_first_name); 
    END view_delete;

    -- Процедура обновления
    PROCEDURE view_update (
        r_new r_view,
        r_old r_view,
        flags r_flags
    ) IS
        new_sal NUMBER;
        r_change r_view;
    BEGIN
        new_sal := analyze_salary(r_new.v_salary);
        IF (flags.v_salary)
        THEN
            IF (new_sal != r_old.v_salary)--(check_sal(r_new.v_salary))
            THEN
                UPDATE employees
                SET salary = new_sal/* to_number(
                    regexp_substr(
                        substr(
                            r_new.v_salary,1,
                            length(r_new.v_salary) - 1
                        ),'^[[:digit:]]+$'
                    )
                )*/
                WHERE last_name = initcap(r_old.v_last_name)
                AND first_name = initcap(r_old.v_first_name);
            ELSE RAISE wrong_salary;
            END IF;
        END IF;
        
        IF (flags.v_last_name) THEN
        IF (r_new.v_last_name IS NOT NULL) THEN
            UPDATE employees
            SET last_name = initcap(r_new.v_last_name)
            WHERE first_name = initcap(r_new.v_first_name)
            AND last_name = initcap(r_old.v_last_name);

            UPDATE employees
            SET email = upper(substr(r_new.v_first_name,1,1)
                || substr(replace(r_new.v_last_name,' ',''),1,7))
            WHERE first_name = initcap(r_old.v_first_name)
            AND last_name = initcap(r_old.v_last_name);
        ELSE RAISE null_last_name;
        END IF;
        END IF;
        
        IF (flags.v_first_name)
        THEN
            UPDATE employees
            SET first_name = initcap(r_new.v_first_name)
            WHERE first_name = initcap(r_old.v_first_name)
            AND last_name = initcap(r_old.v_last_name);
        END IF;

    END view_update;

    INSTEAD OF EACH ROW IS BEGIN
        r_new.v_last_name := :new."Last_Name";
        r_new.v_first_name := :new."First_Name";
        r_new.v_salary := :new."Salary";
        r_old.v_last_name := :old."Last_Name";
        r_old.v_first_name := :old."First_Name";
        r_old.v_salary := :old."Salary";

        IF (r_new.v_last_name != r_old.v_last_name)
        THEN flags.v_last_name := true;
        ELSE flags.v_last_name := false;
        END IF;

        IF (r_new.v_first_name != r_old.v_first_name)
        THEN flags.v_first_name := true;
        ELSE flags.v_first_name := false;
        END IF;

        IF (r_new.v_salary != r_old.v_salary)
        THEN flags.v_salary := true;
        ELSE flags.v_salary := false;
        END IF;

        IF inserting THEN
            view_insert(r_new);
        ELSIF updating THEN
            view_update(r_new,r_old,flags);
        ELSIF deleting THEN
            view_delete(r_old);
        END IF;

    EXCEPTION
        WHEN wrong_salary THEN
            raise_application_error(-20501, 'Неверное значение з/п!');

        WHEN null_last_name THEN
            raise_application_error(-20502, 'Фамилия не может быть пустая!');

        WHEN dup_val_on_index THEN
            raise_application_error(-20503, 'Нарушено ограничение уникальности!');

    END INSTEAD OF EACH ROW;
END edit_view_trg;
...
Рейтинг: 0 / 0
13.05.2021, 16:45
    #40070055
dmdmdm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stravicki
в чем проблема не вижу.


Не увидите, пока будете сразу совать в to_number многоэтажную шляпу без проверок.

Код: plsql
1.
2.
to_number(
            regexp_substr(...
...
Рейтинг: 0 / 0
13.05.2021, 16:46
    #40070056
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Или в :new."Salary" не сможет быть записана строка "Salary" ||'+'||'8000$'?
...
Рейтинг: 0 / 0
13.05.2021, 16:47
    #40070057
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
dmdmdm,

в обычно селекте все работает ок
...
Рейтинг: 0 / 0
13.05.2021, 16:49
    #40070058
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stravicki,

строку с ошибкой не показывает?

навскидку

FUNCTION check_sal (
sal VARCHAR2
) RETURN BOOLEAN IS

RETURN to_number(check_sal(sal));

.....
stax
...
Рейтинг: 0 / 0
13.05.2021, 16:53
    #40070061
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stax,

65 строка - это RETURN в функции analyze_salary
А авторRETURN BOOLEAN IS - для проверки з/п при установке, например, просто "Salary" = '8000$' (без +,-,* и т.п.)
...
Рейтинг: 0 / 0
13.05.2021, 17:05
    #40070067
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stravicki
Stax,

65 строка - это RETURN в функции analyze_salary
А авторRETURN BOOLEAN IS
- для проверки з/п при установке, например, просто "Salary" = '8000$' (без +,-,* и т.п.)

хочете чтоб я строки номеровал

ELSIF check_sal(sal) = TRUE THEN
RETURN to_number(check_sal(sal));

я ж написал check_sal(sal) return boolean
to_number(от boolean)?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
SQL> ed
Wrote file afiedt.buf

  1  declare
  2  v number;
  3  FUNCTION check_sal (
  4          sal VARCHAR2
  5      ) RETURN BOOLEAN IS
  6  begin
  7   return true;
  8  end;
  9  begin
 10   v:=to_number(check_sal('a'));
 11* end;
SQL> /
 v:=to_number(check_sal('a'));
    *
ERROR at line 10:
ORA-06550: line 10, column 5:
PLS-00306: wrong number or types of arguments in call to 'TO_NUMBER'
ORA-06550: line 10, column 2:
PL/SQL: Statement ignored



ps
мож
ELSIF check_sal(sal) = TRUE THEN
RETURN to_number(sal);

pss
можна ELSIF check_sal(sal) THEN
......
stax
...
Рейтинг: 0 / 0
13.05.2021, 17:39
    #40070088
Stravicki
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Триггер на представление
Stax,

Спасибо! Понял в чем ошибка)
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Триггер на представление / 18 сообщений из 18, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]