Модераторы: skyboy
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Триггеры или куда делись CHECK и ASSERTION 
V
    Опции темы
UsamaBrainLaden
Дата 10.11.2008, 00:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 10.11.2008

Репутация: нет
Всего: нет



Никак не могу организовать бизнес-правила! 
CHEK не работает, а в мануалах по триггерам указаны в основном опреация SET. Можно ли с помощью триггера отменять удаление в событии BEFORE DELETE (или другом) при неудовлетворении какого-то логического условия?
Скажем если пользователь пытается добавить запись, которая не удовлетворяет какому-то условию, которое проверяет триггер, то происходит отмена операции (типа Break в циклах паскаля).
ЗЫ:
Дело в том что в книге по SQL четко описаны реализации ограничений всех типов, даже которые накладываются на запись таблицы. Одним из способов это просто вставка в конце таблицы CHECK и какого-то условия которое проверяется при каждой ее модификации и соответственно отменяет опреацию в случае неудачи. В пятой версии MySQL всю эту прелесть отменили походу и ничего не остается как подумать что это можно реализовать через триггеры, но я не исключаю того, что это можно сделать и другими средствами, вопрос только какими?
PM MAIL   Вверх
sir_nuf_nuf
Дата 13.11.2008, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 8
Всего: 31



Да.. CHECK что то действительно не реализован в MySQL
А с каким движком вы хотите это использовать ?
Если с InnoDB - то есть предложение повесить триггер BEFORE INSERT / UPDATE и откатывать транзакцию, если проверка не прошла..(Как это красиво реализовать другая тема.)

А если не транзакционный движок (MyISAM например),  то нужно предложить какую-то замену вставляемому значению, например оставлять старым..

вот пример тригеров:

Код

delimiter $$

drop trigger if exists UCHECK $$
create definer = zif trigger UCHECK
before update on te
for each row
begin
  if NEW.n < 10 then
    set NEW.n = OLD.n;
  end if;
end;$$


drop trigger if exists ICHECK $$
create definer = zif trigger ICHECK
before insert on te
for each row
begin
  if NEW.n < 10 then
    set NEW.n = NULL;
  end if;
end;

$$


при нарушении условия при INSERT - вставляет NULL
при нарушении условия при UPDATE - оставляет старым

ну так.. для справки:
Код

DROP TABLE IF EXISTS `test`.`te`;
CREATE TABLE  `test`.`te` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `n` int(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;


Это сообщение отредактировал(а) sir_nuf_nuf - 13.11.2008, 12:45


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
UsamaBrainLaden
Дата 13.11.2008, 18:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 10.11.2008

Репутация: нет
Всего: нет



Я так понимаю innoDB транзакционный движок?
То есть фактически мне нужно при создании таблицы в конце указать innoDB, а потом создать триггер, скажем после удаления (AFTER DELETE) и если меня уловие не устроит то откатывать (ROLLBACK) так я понял?
Дело в том что удаление происходит не через транзакцию, а просто так. В Delphi через компонент DBNavigator. Ясно что все равно происходит посылка запроса (DELETE FROM), но опять же никакой транзакции нет, или сам движок innoDB выполняет запросы к таблицам вкладывая их в транзакцию?

Дело втом что меня не устраивает немного забивание NULL'ом и вообще больше озобочен процессом отмены удаления записи если пользователь (вернее его код) не совпадает с кодом владельца записи.
PM MAIL   Вверх
UsamaBrainLaden
Дата 13.11.2008, 19:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 10.11.2008

Репутация: нет
Всего: нет



Если я делаю так:

Код

CREATE TABLE mans
(
    man_id    MEDIUMINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name    CHAR (10)
) ENGINE = innoDB;

CREATE TABLE books
(
    book_id    MEDIUMINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    named    CHAR (20),
    owner    MEDIUMINT NOT NULL,
        FOREIGN KEY ni (owner) REFERENCES mans (man_id)
        ON DELETE CASCADE
) ENGINE = innoDB;

delimiter //

CREATE TRIGGER books_trigger
AFTER DELETE
ON books FOR EACH ROW
IF (OLD.owner <> SUBSTRING_INDEX(USER(),'@',1)) THEN ROLLBACK; END IF;
//
delimiter ;


То он ругается на то что откат транзакции не может производиться внутри триггера!
PM MAIL   Вверх
sir_nuf_nuf
Дата 14.11.2008, 22:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 8
Всего: 31



UsamaBrainLaden,  InnoDB - транзакционный.

А) Любая DML операция происходит в рамках транзакции. Возможен режим autocommit, когда для каждого оператора - открывается своя транзакция, скорее всего ваш дельфи-компонент работает именно в autocommit. Но это не суть.

Б) у MySQL куча ограничений на триггеры. по хорошему явно вызывать ROLLBACK не нужно.
вызов этого оператора предполагает, что вы продолжите дальш работу, а вам нужно прервать выполнение. 
Так что бы MySQL сам откатил транзакцию. Сейчас погуглю поэтому поводу.

А пока есть костыль для прерывания транзакции: заместо ROLLBACK вызовите несуществующую функциию.
Код

CALL SOME_NOT_EXISTING_FUNCTION();



--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
UsamaBrainLaden
Дата 15.11.2008, 18:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 10.11.2008

Репутация: нет
Всего: нет



Действительно работает))

я правда немного неправильно написал триггер:

Код

delimiter //

CREATE TRIGGER books_trigger
AFTER DELETE
ON books FOR EACH ROW
IF (OLD.owner <> 
(
select man_id
from mans
where name = SUBSTRING_INDEX(USER(),'@',1)
)
)THEN CALL SOME_F(); END IF;
// :offtopic 
delimiter ;


просто выдается ошибка о несуществующей функции и запись остается во своясе, а для пользователя - владельца записи процесс удаления проходит нормально, тока сами понимаете это же не выход, как-то не по русски получается!
PM MAIL   Вверх
sir_nuf_nuf
Дата 16.11.2008, 20:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 8
Всего: 31



UsamaBrainLaden,  да пожалуй не по-русски. но судя по форумам и докам 
А) CHECK в MySQL пока что не реализован
Б) exceptions тоже не реализованы.  Хотя это обычный способ сообщать о нарушениях бизнес правил на уровне БД. Есть костыли для реализации Exceptions. один из них я вам показал. Еще как вариант - писать UDF на C. Ищете по форумам.. 

Но мне кажется что несуществующая функция - приемлемый вариант. Главное имя ей подходящие дайте.., наприрме EMPTY_BALANCE_EXCEPTION.

тогда вызов такой функции будет похож на exception
Код

CALL EMPTY_BALANCE_EXCEPTION();


такой вот syntactic sugar


--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
UsamaBrainLaden
Дата 16.11.2008, 21:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 39
Регистрация: 10.11.2008

Репутация: нет
Всего: нет



А в какая СУБД поддерживает CHECK?
Главное чтобы она была бесплатная,а ещё лучше чтобы это была другая версия MySQL (даже если она коммерческая).
PM MAIL   Вверх
sir_nuf_nuf
Дата 16.11.2008, 23:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 920
Регистрация: 6.1.2008

Репутация: 8
Всего: 31



UsamaBrainLaden, странно.. Postgress поддерживает.
Но выбирать БД стоит по другим критериям =)



--------------------
user posted image
user posted image
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | MySQL | Следующая тема »


 




[ Время генерации скрипта: 0.0492 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.