Удаление старых записей

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
QuAzI
Сообщения: 11
Зарегистрирован: 17 апр 2008, 02:36

Удаление старых записей

Сообщение QuAzI » 29 июн 2009, 17:59

Добрый день
Точно знаю что вопрос дико ламерский, что я где-то туплю, но как сделать такую простую с виду вещь
DELETE FROM MAIN WHERE MAIN.ID_REC>0 AND MAIN.DATE_CR<'01.12.2008'

Если делаю DELETE FROM MAIN WHERE MAIN.ID_REC=1 например то запись удаляется. Но мне нужно прочистить всё, оставив первую запись и последние несколько рабочих месяцев.

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Re: Удаление старых записей

Сообщение dimitr » 30 июн 2009, 08:26

и что не устраивает в приведенном операторе?
DELETE FROM MAIN WHERE MAIN.ID_REC>0 AND MAIN.DATE_CR<'01.12.2008'

QuAzI
Сообщения: 11
Зарегистрирован: 17 апр 2008, 02:36

Re: Удаление старых записей

Сообщение QuAzI » 30 июн 2009, 09:58

Ну, что-то не устраивает

SQL> DELETE FROM MAIN
CON> WHERE (MAIN.ID_REC>0) and (MAIN.DATE_CR<'01.12.2008');
Statement failed, SQLCODE = -508

no current record for fetch operation
-attempted update of read-only column

В таблице MAIN 892 записи

Код: Выделить всё

SQL> show table main;
ID_REC                          INTEGER Not Null
ID_PARENT                       INTEGER Not Null DEFAULT -1
JARLIK                          (D_JARLIK) VARCHAR(15) Nullable
DATE_CR                         DATE Not Null DEFAULT 'NOW'
TIME_CR                         TIME Not Null DEFAULT 'NOW'
ID_BAG                          INTEGER Not Null DEFAULT 1
ID_KAT                          INTEGER Not Null DEFAULT 0
ID_OBJ                          INTEGER Not Null DEFAULT 0
ID_STATE                        INTEGER Not Null DEFAULT 0
INDEX_OTP                       (D_INDEX) INTEGER Not Null DEFAULT 0
INDEX_POL                       (D_INDEX) INTEGER Not Null DEFAULT 0
INDEX_NEXT                      (D_INDEX) INTEGER Not Null DEFAULT 0
INDEX_PREV                      (D_INDEX) INTEGER Not Null DEFAULT 0
ID_USER                         INTEGER Not Null DEFAULT 0
ID_PLACE                        INTEGER Not Null DEFAULT 0
ID_ROUTE                        INTEGER Not Null DEFAULT 0
MASSA                           INTEGER Not Null DEFAULT 0
RECIEVED                        INTEGER Not Null  DEFAULT 0
OLD_PARENT                      INTEGER Not Null DEFAULT 0
TR_TIP                          CHAR(1) Nullable
TR_NOMER                        VARCHAR(10) Nullable
TR_FIO                          VARCHAR(60) Nullable
CONSTRAINT PK_MAIN:
  Primary key (ID_REC)

Triggers on Table MAIN:
MAIN_BIUD0, Sequence: 0, Type: BEFORE INSERT OR UPDATE OR DELETE, Active
MAIN_AIUD0, Sequence: 0, Type: AFTER INSERT OR UPDATE OR DELETE, Active
Триггеры на удаление не влияют, по одной записи удаляется легко и непринуждённо.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Удаление старых записей

Сообщение Dimitry Sibiryakov » 30 июн 2009, 14:36

Значит всё-таки влияют, просто по одной ты не добираешься до записи, на которой запрос обламывается. Не нужно в after-триггерах присваивать что-то new или old. А в before-триггерах - только old.

QuAzI
Сообщения: 11
Зарегистрирован: 17 апр 2008, 02:36

Re: Удаление старых записей

Сообщение QuAzI » 30 июн 2009, 16:08

Вот первый триггер, который before

Код: Выделить всё

AS
BEGIN
 IF (INSERTING) THEN
  BEGIN
   IF (NEW.ID_REC IS NULL) THEN NEW.ID_REC = GEN_ID(GEN_MAIN_ID,1);
   IF (NEW.ID_STATE BETWEEN 301 AND 302) THEN NEW.RECIEVED=1;
  END 
 IF (UPDATING) THEN
  BEGIN
   IF (NEW.MASSA<0) THEN NEW.MASSA=0;
   IF (NEW.ID_STATE=102) THEN
    BEGIN
     NEW.RECIEVED=1;
     IF (OLD.ID_STATE<>101) THEN
      BEGIN
       NEW.ID_STATE=OLD.ID_STATE;
      END
    END ELSE
    BEGIN
     IF ((OLD.ID_STATE=101) AND ((NEW.ID_BAG=1) OR (NEW.ID_BAG=2))) THEN
      BEGIN
       NEW.OLD_PARENT=OLD.ID_PARENT;
      END
     IF (NEW.ID_STATE=501) THEN
      BEGIN
       IF ((NEW.RECIEVED=0) OR (NEW.ID_BAG<>1)) THEN NEW.ID_STATE=OLD.ID_STATE;
      END
     IF ((NEW.ID_STATE=1) AND (NEW.ID_BAG=2)) THEN NEW.ID_PARENT=0;
     IF (NEW.ID_STATE IN (401,402,403)) THEN
      BEGIN
       IF ((NEW.ID_BAG=2) AND (NEW.ID_PARENT<=0)) THEN
        BEGIN
         NEW.ID_STATE=OLD.ID_STATE;
        END
      END 
    END
  END
END
Вот второй, который after

Код: Выделить всё

AS
BEGIN
 IF (INSERTING) THEN
  BEGIN
   INSERT INTO MOVE (ID_MAIN, ID_OPER, ID_USER)
             VALUES (NEW.ID_REC, NEW.ID_STATE, NEW.ID_USER);
   IF ((NEW.ID_PARENT>0) AND (NEW.MASSA>0)) THEN
    BEGIN
     UPDATE MAIN SET MASSA=MASSA+NEW.MASSA WHERE ID_REC=NEW.ID_PARENT;
    END
  END

 IF (UPDATING) THEN
  BEGIN
   IF (NEW.ID_PARENT<>OLD.ID_PARENT) THEN
    BEGIN
     IF (NEW.ID_PARENT>0) THEN
      BEGIN
       IF (NEW.MASSA>0) THEN
        BEGIN
         UPDATE MAIN SET MASSA=MASSA+NEW.MASSA WHERE ID_REC=NEW.ID_PARENT;
        END 
      END
     IF (OLD.ID_PARENT>0) THEN
      BEGIN
       IF (OLD.MASSA>0) THEN
        BEGIN
         UPDATE MAIN SET MASSA=MASSA-OLD.MASSA WHERE ID_REC=OLD.ID_PARENT;
        END 
      END
    END ELSE
    BEGIN
     IF ((NEW.MASSA<>OLD.MASSA) AND (NEW.ID_PARENT>0)) THEN
      BEGIN
       UPDATE MAIN SET MASSA=(MASSA-OLD.MASSA+NEW.MASSA)
        WHERE ID_REC=NEW.ID_PARENT;
      END
    END
   IF ((NEW.ID_STATE<>OLD.ID_STATE) AND (NEW.ID_STATE<>-1)) THEN
    BEGIN
     INSERT INTO MOVE (ID_MAIN, ID_OPER, ID_USER)
               VALUES (NEW.ID_REC, NEW.ID_STATE, NEW.ID_USER);
     IF (NEW.ID_STATE=1) THEN
      BEGIN
       IF (NEW.ID_BAG=2) THEN
         UPDATE MAIN SET ID_PARENT=OLD.ID_PARENT WHERE ID_PARENT=NEW.ID_REC;
       IF (NEW.ID_BAG=3) THEN
        BEGIN
         IF (NEW.ID_KAT=3) THEN
          BEGIN
           UPDATE MAIN SET ID_PARENT=0, ID_STATE=0 WHERE ID_PARENT=NEW.ID_REC;
          END ELSE
          BEGIN
           UPDATE MAIN SET ID_PARENT=0 WHERE ID_PARENT=NEW.ID_REC;
          END
        END
      END ELSE
      BEGIN
       IF (NEW.ID_STATE=498) THEN
         UPDATE MAIN SET ID_STATE=NEW.ID_STATE, INDEX_PREV=NEW.INDEX_PREV,
                         INDEX_NEXT=NEW.INDEX_NEXT
          WHERE ID_PARENT=NEW.ID_REC;
       IF (NEW.ID_STATE<>498) THEN
         UPDATE MAIN SET ID_STATE=NEW.ID_STATE WHERE ID_PARENT=NEW.ID_REC;
       IF ((NEW.ID_STATE BETWEEN 501 AND 503) AND (NEW.ID_BAG=1)) THEN
        BEGIN
         UPDATE DESC_PO
            SET NOMER_IZV=(SELECT MAX(D.NOMER_IZV)+1 FROM DESC_PO D)
          WHERE ID_MAIN=NEW.ID_REC;
        END 
      END
    END
   IF ((NEW.RECIEVED=1) AND (OLD.RECIEVED=0) AND (OLD.ID_STATE<>101)) THEN
    BEGIN
     INSERT INTO MOVE (ID_MAIN, ID_OPER, ID_USER)
               VALUES (NEW.ID_REC, 102, NEW.ID_USER);
     UPDATE MAIN SET ID_STATE=102 WHERE OLD_PARENT=NEW.ID_REC;
    END
  END

 IF (DELETING) THEN
  BEGIN
   DELETE FROM DESC_PO WHERE ID_MAIN=OLD.ID_REC;
   DELETE FROM MOVE WHERE ID_MAIN=OLD.ID_REC;
   DELETE FROM MAIN WHERE ID_PARENT=OLD.ID_REC;
   IF ((OLD.ID_PARENT>0) AND (OLD.MASSA>0)) THEN
    BEGIN
     UPDATE MAIN SET MASSA=MASSA-OLD.MASSA WHERE ID_REC=OLD.ID_PARENT;
    END
  END
 IF ((OLD.ID_STATE BETWEEN 101 AND 199) OR
     (NEW.ID_STATE BETWEEN 101 AND 199)) THEN POST_EVENT 'REFRESH_PRIEM';
 IF ((OLD.ID_STATE BETWEEN 201 AND 299) OR
     (NEW.ID_STATE BETWEEN 201 AND 299)) THEN POST_EVENT 'REFRESH_OBRIN';
 IF ((OLD.ID_STATE BETWEEN 301 AND 399) OR
     (NEW.ID_STATE BETWEEN 301 AND 399)) THEN POST_EVENT 'REFRESH_OBROUT';
 IF ((OLD.ID_STATE BETWEEN 401 AND 499) OR
     (NEW.ID_STATE BETWEEN 401 AND 499)) THEN POST_EVENT 'REFRESH_OTPR';
 IF ((OLD.ID_STATE BETWEEN 501 AND 599) OR
     (NEW.ID_STATE BETWEEN 501 AND 599)) THEN POST_EVENT 'REFRESH_DOST';
END
Что тут может мешать? Думаю ещё backup/restore сделать, а то такое поведение гнусно пахнет.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Удаление старых записей

Сообщение Dimitry Sibiryakov » 01 июл 2009, 13:59

А теперь копай вглубь, проверяй весь каскад по ветке

Код: Выделить всё

IF (DELETING) THEN
  BEGIN
   DELETE FROM DESC_PO WHERE ID_MAIN=OLD.ID_REC;
   DELETE FROM MOVE WHERE ID_MAIN=OLD.ID_REC;
   DELETE FROM MAIN WHERE ID_PARENT=OLD.ID_REC;
   IF ((OLD.ID_PARENT>0) AND (OLD.MASSA>0)) THEN
    BEGIN
     UPDATE MAIN SET MASSA=MASSA-OLD.MASSA WHERE ID_REC=OLD.ID_PARENT;
    END
  END
PS: Попытка апдейта только что удалённой родительской записи выглядит готичненько...

Ответить