Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Ограничение на поле


Страницы:   1 2 3

}|{yk ©   (2004-03-31 13:19:00) 

Как сделать ограничение на поле? Оно может принимать или значение из таблицы, или -1 (для дерева). В констрейнт не получается - нельзя подзапросы писать, с вьюхой связать тоже нельзя. А вообще как-то реализовывать можно? Можно конечно триггер написать, но это как-то неправильно...


}|{yk   (2004-03-31 16:16:00) [21]

наверно в 9 можно exists использовать в pl/sql. А в 8 нельзя


Курдль   (2004-03-31 16:14:00) [22]


> Johnmen ©   (31.03.04 16:00) [21]
> >Курдль ©   (31.03.04 15:48) [19]
>
> Как выглядит источник ошибки ?


ОК! Для установления истины не поленился модифицировать код [8] по Вашим рекомендациям.


create or replace trigger TSK_GROUP_LOOP
 before insert or update on PR_TASKS
 for each row
--  when (NEW.TSK_ID_PR is not null)
declare
 ex_GROUP_LOOP        EXCEPTION;

begin

 if exists
    (select 1
     from PR_TASKS T
     where T.TSK_ID = :NEW.TSK_ID
     and rownum = 1
     start with T.TSK_ID = :NEW.TSK_ID_PR
     connect by prior T.TSK_ID_PR = T.TSK_ID;
    )
 then RAISE ex_GROUP_LOOP;
 end if;
 
EXCEPTION
 WHEN ex_GROUP_LOOP THEN
   Raise_application_error(-20103, 'Ïîïûòêà "êîëüöåâîé ãðóïïèðîâêè"');
 WHEN OTHERS then
   Raise_application_error(-20002, SQLERRM);
end TSK_GROUP_LOOP;


PL/SQL Developer отругался на нее, как было указано в [19]


Johnmen   (2004-03-31 16:00:00) [23]

>Курдль ©   (31.03.04 15:48) [19]

Как выглядит источник ошибки ?


}|{yk   (2004-03-31 15:58:00) [24]

PLS-00204 function or pseudo-column 'exists' may be used inside a SQL statement only

Cause: A pseudocolumn or proscribed function was used in a procedural statement. The SQL pseudocolumns (CURRVAL, LEVEL, NEXTVAL, ROWID, ROWNUM) can be used only in SQL statements. Likewise, certain functions such as DECODE, DUMP, and VSIZE and the SQL group functions (AVG, MIN, MAX, COUNT, SUM, STDDEV, VARIANCE) can be used only in SQL statements.

Action: Remove the pseudocolumn reference or function call from the procedural statement. Or, replace the procedural statement with a SELECT INTO statement; for example, replace:bonus := DECODE(rating, 1, 5000, 2, 2500, ...); with the following statement: SELECT DECODE(rating, 1, 5000, 2, 2500, ...) INTO bonus FROM dual;


Курдль   (2004-03-31 15:48:00) [25]


> Точно ? Проверено ? А если ошибка, то какая ?


В случае замены в коде [8] на if exists ошибка следующая:

"Неверная переменная привязки:
start with T.TSK_ID = :NEW.TSK_ID_PR"


Johnmen   (2004-03-31 15:10:00) [26]

>}|{yk ©   (31.03.04 14:44) [16]
>Нет, в триггерах так нельзя
>Exists можно использовать только в предложениях SQL

Точно ? Проверено ? А если ошибка, то какая ?


DenK_vrtz   (2004-03-31 14:56:00) [27]

Чтобы не мучали проблемы мутации можно написать view и триггер к нему


}|{yk   (2004-03-31 14:44:00) [28]

2Johnmen ©   (31.03.04 14:20) [14]
Нет, в триггерах так нельзя
Exists можно использовать только в предложениях SQL


Курдль   (2004-03-31 14:34:00) [29]


> А зачем
> and rownum = 1 ?


> Кстати, а что select 1 from ... будет быстрее для случая
> определения существования чем select count(*) from ?

Объединяя 2 вопроса.
1. Это чтобы запрос сдох сам по себе после того, как на первой же строке стало ясно, что "тест положительный".
2. count(*)будет упорно пересчитывать все записи
3. Не помню, почему было отказано в применении конструкции if exists .... :)


Johnmen   (2004-03-31 14:20:00) [30]

>}|{yk ©   (31.03.04 14:08) [12]
>Кстати, а что select 1 from ... будет быстрее для случая >определения существования чем select count(*) from ?

Наиболее быстро
IF EXISTS(SELECT 1 FROM line)
THEN


}|{yk   (2004-03-31 14:15:00) [31]

Окончательный триггер таков

CREATE OR REPLACE TRIGGER APP_LINE_REPORT_TRG
BEFORE
INSERT OR UPDATE
ON APP_LINE_REPORT
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
DECLARE
  col                NUMBER;
  vr_is_exists       INTEGER;
  ex_group_loop      EXCEPTION;
  ex_unknown_ident   EXCEPTION;
BEGIN
  SELECT COUNT (*)
    INTO col
    FROM line a
   WHERE a.mem_id = :NEW.mem_pid;

  IF (col = 0)
  THEN
     IF (:NEW.mem_pid -1)
     THEN
        RAISE ex_unknown_ident;
     END IF;
  END IF;

  SELECT     1
        INTO vr_is_exists
        FROM app_line_report t
       WHERE t.mem_id = :NEW.mem_id AND ROWNUM = 1
  START WITH t.mem_id = :NEW.mem_pid
  CONNECT BY PRIOR t.mem_pid = t.mem_id;

  IF vr_is_exists IS NOT NULL
  THEN
     RAISE ex_group_loop;
  END IF;
EXCEPTION
  WHEN ex_group_loop
  THEN
     raise_application_error (-20101,
                              'Îøèáêà: "ïîïûòêà êîëüöåâîé ãðóïïèðîâêè"'
                             );
  WHEN ex_unknown_ident
  THEN
     raise_application_error (-20102, 'Îøèáêà: Íåèçâåñòíûé èäåíòèôèêàòîð!');
END app_line_report_trg;
/


}|{yk   (2004-03-31 14:08:00) [32]

Кстати, а что select 1 from ... будет быстрее для случая определения существования чем select count(*) from ?


}|{yk   (2004-03-31 14:04:00) [33]

А зачем
and rownum = 1 ?
Спасибо за код


Курдль   (2004-03-31 13:57:00) [34]

Ну и как, скушало? :)


}|{yk   (2004-03-31 13:56:00) [35]

Вобщем вот так решил
CREATE OR REPLACE TRIGGER app_line_report_trg
  BEFORE INSERT OR UPDATE
  ON app_line_report
  REFERENCING OLD AS OLD NEW AS NEW
  FOR EACH ROW
DECLARE
  col   NUMBER;
BEGIN
  SELECT COUNT (*)
    INTO col
    FROM line a
   WHERE a.mem_id = :NEW.mem_pid;

  IF (col = 0)
  THEN
     IF (:NEW.mem_pid -1)
     THEN
        raise_application_error (-20501, 'Íåèçâåñòíûé èäåíòèôèêàòîð!');
     END IF;
  END IF;
END;


Курдль   (2004-03-31 13:47:00) [36]

Рабочий пример похожего триггера (оракл 9)

create or replace trigger TSK_GROUP_LOOP
 before insert or update on PR_TASKS
 for each row
--  when (NEW.TSK_ID_PR is not null)
declare
 vr_IS_EXISTS         INTEGER;
 ex_GROUP_LOOP        EXCEPTION;

begin

 select 1 into vr_IS_EXISTS
 from PR_TASKS T
 where T.TSK_ID = :NEW.TSK_ID
 and rownum = 1
 start with T.TSK_ID = :NEW.TSK_ID_PR
 connect by prior T.TSK_ID_PR = T.TSK_ID;
 
 if vr_IS_EXISTS is not Null    
 then RAISE ex_GROUP_LOOP;
 end if;
 
EXCEPTION
 WHEN ex_GROUP_LOOP THEN
   Raise_application_error(-20103, 'Ошибка: "попытка кольцевой группировки"');
 WHEN OTHERS then
   Raise_application_error(-20002, SQLERRM);
end TSK_GROUP_LOOP;


Vlad   (2004-03-31 13:33:00) [37]


> Курдль ©   (31.03.04 13:30) [5]


> ! Никакой мутации не будет.

А что, разве мутация возникает только при записи ? :-)

> }|{yk ©   (31.03.04 13:26) [4]

Вобще, достаточно неплохая практика - делать все изменения в базе через ХП. Это поможет и мутации избежать.


Johnmen   (2004-03-31 13:31:00) [38]

>В констрейнт не получается - нельзя подзапросы писать

А как пробовал, что не получилось ?

>просто так вызовет мутацию таблицы. Или я не прав?

Мутацию можно отключить.

Все верно сказали про триггеры. Более того и констрейнты тоже реализуются через триггеры, системные.


Курдль   (2004-03-31 13:30:00) [39]


> вызовет мутацию таблицы

Вы же не будете писать, а только контролировать! Никакой мутации не будет.
А насчет "муторно" - 3 строки текста :)


}|{yk   (2004-03-31 13:26:00) [40]

Oracle 8.1.7
Просто each row триггер писать на insert/update в Oracle муторно, просто так вызовет мутацию таблицы. Или я не прав?


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо