WildSery писал(а):Ты бы прекратит хнёй заниматься, а написал лучше по-русски, чего тебе надо добиться.
Я попытался прочитать твои откровения внимательно - чуть мозг не вывихнул. Больше на бред похоже, чем на код.
Но укрепился в стойком подозрении, что ты делаешь совсем не то, что надо.
Там вот так:
Есть таблица DEAL, хранящая суммы по каждой сделке в поле DEALSUM. Сделки имеют внешний ключ учетного периода FK_MONTH_NO и отдела FK_DEPT_NO
Код: Выделить всё
CREATE TABLE DEAL(
DEAL_NO INTEGER NOT NULL,
FK_DEPT_NO INTEGER,
FK_MONTH_NO INTEGER,
DEALSUM DECIMAL(9,2) DEFAULT 0
);
Есть таблица REPORT_INFO, в полях которой надо производить различные расчеты при любом изменении в таблице DEAL.
К примеру, пробегаться в DEAL по всем сделкам данного периода и отдела, пересчитывать удельный порог доходности для каждой сделки, после чего вносить информацию в REPORT_INFO.DEAL_PDN.
Код: Выделить всё
CREATE TABLE REPORT_INFO(
REPORT_INFO_NO INTEGER NOT NULL,
FK_DEAL_NO INTEGER NOT NULL,
FK_MONTH_NO INTEGER NOT NULL,
FK_DEPT_NO INTEGER NOT NULL,
PDN_SUM DECIMAL(9,2) DEFAULT 0, /* сумма ПДН для отдела, которому принадлежит сделка (копируется из таблицы PDN) */
DEAL_SUM DECIMAL(9,2) DEFAULT 0, /* сумма сделки (копируется из DEAL) */
DEAL_PDN DECIMAL(9,2) DEFAULT 0, /* удельный ПДН для сделки. Равен: (сумма данной сделки / суммы всех сделок отдела по периоду) * PDN_SUM, то есть ПДН отдела за период */
);
Что я делаю:
Использую триггер для таблички DEAL, в котором вызываю процедуру
Код: Выделить всё
CREATE TRIGGER TR_DEALS_SUM_FOR_PDN FOR DEAL
ACTIVE AFTER INSERT OR UPDATE OR DELETE POSITION 0
AS
DECLARE VARIABLE MONZ_NO INTEGER = 0;
DECLARE VARIABLE DEPT_NO INTEGER = 0;
DECLARE VARIABLE DEAL_NO INTEGER = 0;
DECLARE VARIABLE IS_MAKE SMALLINT = 0;
DECLARE VARIABLE IS_EXISTS SMALLINT = 0;
/*
При любом изменении в суммах и активности сделок
1. Если сделка добавляется, добавим соответствие в REPORT_INFO
Если удаляется - удалим из REPORT_INFO
2. Вызываем процедуру обновления таблицы отчетов
*/
BEGIN
-- 1.
IF (INSERTING OR UPDATING) THEN
BEGIN
MONZ_NO = NEW.FK_MONTH_NO;
DEPT_NO = NEW.FK_DEPT_NO;
DEAL_NO = NEW.DEAL_NO;
IS_MAKE = NEW.MAKE;
END
ELSE IF (DELETING) THEN
BEGIN
MONZ_NO = OLD.FK_MONTH_NO;
DEPT_NO = OLD.FK_DEPT_NO;
DEAL_NO = OLD.DEAL_NO;
IS_MAKE = OLD.MAKE;
END
-- приводим записи REPORT_INFO в соответствие с DEAL
SELECT COUNT(*) FROM REPORT_INFO
WHERE FK_DEAL = :DEAL_NO
INTO :IS_EXISTS;
IF (INSERTING AND IS_MAKE=1) THEN
INSERT INTO REPORT_INFO(FK_DEAL, FK_MONTH, FK_DEPT)
VALUES(:DEAL_NO, :MONZ_NO, :DEPT_NO);
ELSE IF (UPDATING) THEN
BEGIN
IF ((IS_MAKE=1) AND (IS_EXISTS=0)) THEN
INSERT INTO REPORT_INFO(FK_DEAL, FK_MONTH, FK_DEPT)
VALUES(:DEAL_NO, :MONZ_NO, :DEPT_NO);
ELSE IF (IS_MAKE=0) THEN
DELETE FROM REPORT_INFO
WHERE FK_DEAL = :DEAL_NO;
END
ELSE IF (DELETING) THEN
DELETE FROM REPORT_INFO
WHERE FK_DEAL = :DEAL_NO;
-- 2
EXECUTE PROCEDURE PR_UPD_REPORT_INFO(:DEPT_NO, :MONZ_NO);
END
;
Процедура вот такая
Код: Выделить всё
CREATE PROCEDURE PR_UPD_REPORT_INFO (
DEPT_NO INTEGER,
MONZ_NO INTEGER
)
AS
DECLARE VARIABLE PDN_SUM DECIMAL(15,3) = 0;
DECLARE VARIABLE ALL_DEAL_SUM DECIMAL(15,3) = 0;
DECLARE VARIABLE ALL_EXP_SUM DECIMAL(15,3) = 0;
DECLARE VARIABLE CURR_DEAL_CURSOR CURSOR FOR
(SELECT D.DEAL_NO, D.DEALSUM
FROM DEAL D
WHERE D.FK_MONTH_NO = :MONZ_NO
AND D.FK_DEPT_NO = :DEPT_NO
AND D.MAKE = 1);
DECLARE VARIABLE CURR_DEAL_ID INTEGER = 0;
DECLARE VARIABLE CURR_DEAL_SUM DECIMAL(15,3) = 0;
DECLARE VARIABLE PDN_FOR_DEAL DECIMAL(15,5) = 0;
DECLARE VARIABLE CURR_EXP_CURSOR CURSOR FOR
(SELECT SUM(E.VAL)
FROM EXPENDS_IN_DEAL E
WHERE E.FK_DEAL = :CURR_DEAL_ID);
BEGIN
-- 1
SELECT
P.PDN FROM PDN P
WHERE
P.FK_DEPT_NO = :DEPT_NO AND
P.FK_MONTH_NO = :MONZ_NO
INTO :PDN_SUM;
-- 2
SELECT
SUM(D.DEALSUM) FROM DEAL D
WHERE
D.FK_DEPT_NO = :DEPT_NO AND
D.FK_MONTH_NO = :MONZ_NO AND
D.MAKE = 1
INTO :ALL_DEAL_SUM;
-- 3
OPEN CURR_DEAL_CURSOR;
WHILE (1=1) DO
BEGIN
FETCH CURR_DEAL_CURSOR INTO :CURR_DEAL_ID, :CURR_DEAL_SUM;
IF (ROW_COUNT = 0) THEN
LEAVE;
PDN_FOR_DEAL = :CURR_DEAL_SUM * :PDN_SUM / :ALL_DEAL_SUM;
OPEN CURR_EXP_CURSOR;
FETCH CURR_EXP_CURSOR INTO :ALL_EXP_SUM;
CLOSE CURR_EXP_CURSOR;
UPDATE REPORT_INFO
SET
PDN_SUM = :PDN_SUM,
DEAL_SUM = :CURR_DEAL_SUM,
DEAL_PDN = :PDN_FOR_DEAL,
DEAL_EXP = :ALL_EXP_SUM,
DEAL_PROFIT = :CURR_DEAL_SUM - :PDN_FOR_DEAL - :ALL_EXP_SUM
WHERE
FK_DEAL_NO = :CURR_DEAL_ID;
END
CLOSE CURR_DEAL_CURSOR;
END
;
Там много чего дополнительного в этой процедуре, но главное - в цикле
WHILE (1=1) DO я пробегаю все сделки и для каждой из них привожу в соответствие записи REPORT_INFO.
Вот собственно...
и надеюсь, курсор не в триггере? Если в триггере, то за такое сажать надо.
Признаться я не понял такой категоричной позиции
ВОт тут именно так и поступают
Кроме того, подскажите мне как по-другому реализовать вот такую реакцию:
При добавлении в таблицу X добавить в таблицу Y по одной записи для каждого соответствия в таблице Z...
Я понимаю, что так или иначе надо бежать по таблице Z, а для этого курсор и нужен